JUnit5测试抽象类报错:No ParameterResolver registered for构造方法参数
解决JUnit5构造方法参数解析失败的问题
为啥会报错?
JUnit5默认没法自动识别并注入Storage接口类型的构造方法参数——它不知道该传哪个具体实现类的实例,因为没有注册对应的参数解析器来处理这种自定义接口类型。
怎么解决?
方法1:把测试类改成抽象类,让子类提供具体的Storage实例
把AbstractArrayStorageTest改成抽象类,去掉带参数的构造方法,加个抽象方法让子类返回具体的Storage对象,然后在@BeforeEach里完成初始化:
import org.junit.jupiter.api.BeforeEach; import ru.javawebinar.basejava.storage.Storage; public abstract class AbstractArrayStorageTest { protected Storage storage; // 子类必须实现这个方法,返回具体的Storage实例(比如ArrayStorage) protected abstract Storage createStorage(); @BeforeEach void setUp() { storage = createStorage(); storage.clear(); // 这里添加测试用的保存操作,比如存入测试简历 // storage.save(new Resume("test_id")); } // 编写你的测试方法,比如testSize、testDelete等 }
然后写具体的实现测试类,比如ArrayStorageTest:
import ru.javawebinar.basejava.storage.ArrayStorage; public class ArrayStorageTest extends AbstractArrayStorageTest { @Override protected Storage createStorage() { return new ArrayStorage(); } // 还可以添加针对ArrayStorage的特殊测试方法 }
方法2:用参数化测试一次性测试多个Storage实现
如果想在同一个测试类里覆盖多个Storage实现,用JUnit5的参数化测试配合@MethodSource:
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import ru.javawebinar.basejava.storage.Storage; import ru.javawebinar.basejava.storage.ArrayStorage; import ru.javawebinar.basejava.storage.AnotherStorage; // 你的其他Storage实现类 import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; public class AbstractArrayStorageTest { // 提供所有需要测试的Storage实例 static Stream<Storage> storageProvider() { return Stream.of( new ArrayStorage(), new AnotherStorage() ); } @ParameterizedTest @MethodSource("storageProvider") void testClearAndSave(Storage storage) { storage.clear(); // 执行保存操作并验证结果 Resume testResume = new Resume("test"); storage.save(testResume); assertEquals(1, storage.size()); } // 其他测试方法同理,将Storage作为参数传入即可 }
方法3:自定义参数解析器(不推荐,除非必须)
要是非得保留带参数的构造方法,可以自己写个参数解析器来注入Storage实例,但这种方式比较繁琐,适合特殊场景:
先编写解析器类:
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolver; import ru.javawebinar.basejava.storage.Storage; import ru.javawebinar.basejava.storage.ArrayStorage; public class StorageParameterResolver implements ParameterResolver { @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { // 判断当前参数是否为Storage类型 return parameterContext.getParameter().getType() == Storage.class; } @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { // 返回具体的Storage实例,比如ArrayStorage return new ArrayStorage(); } }
然后在测试类上添加注解,让JUnit使用这个解析器:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import ru.javawebinar.basejava.storage.Storage; @ExtendWith(StorageParameterResolver.class) public class AbstractArrayStorageTest { private Storage storage; public AbstractArrayStorageTest(Storage storage) { this.storage = storage; } @BeforeEach void setUp() { storage.clear(); // 执行保存操作 } // 测试方法... }
为啥之前初始化storage会为null?
之前在方法里初始化时出现null,大概率是时机不对——比如在@BeforeEach执行前就调用了storage,或者初始化代码未正确执行(比如放在静态块中但实例化失败)。用上面前两种方法能确保测试方法执行前,storage已经被正确初始化。
内容的提问来源于stack exchange,提问作者Egor Stepanenko
相关产品推荐
相关产品推荐

