

在第一张截图中,你可以看到我的测试课。这个类使用@ExtendWith({MockitoExtension.class})进行注释,并且测试的服务也使用@InjectMocks进行注释。在第二个屏幕截图中,您可以看到经过测试的服务。
为什么Mockito在这两种情况下都使用长供应商?
发布于 2021-09-07 03:51:27
Mockito在按以下顺序注入模拟时使用不同的战略:
字段注入在您的示例中不起作用,因为服务的字段被声明为final。
由于字段被声明为final,而且您展示的代码片段没有字段初始化器,所以我假设您有一个带有Supplier are的构造函数。例如。
public SomeService(Supplier<String> stringSupplier, Supplier<Long> longTimeSupplier) {
this.stringSupplier = stringSupplier;
this.longTimeSupplier = longTimeSupplier;
}因此,Mockito将尝试构造函数注入,找到带有两个Supplier参数的构造函数,并尝试解析参数。
然后,Mockito在测试中找到两个Supplier模拟,但是由于类型擦除,它无法看到泛型类型。因此,Mockito看到构造函数如下:
public SomeService(Supplier stringSupplier, Supplier longTimeSupplier)Mockito也不能根据参数名称来决定使用哪个Supplier,因为普通的Java没有提供这些信息。因此,模仿者的名字将不会被考虑在内。
像偏执狂这样的库可以读取字节码并提取调试信息来读取参数名,但是Mockito不使用这个库。
因此,Mockito只是注入第一个匹配的模拟,在您的例子中是Supplier<String> stringSupplier。即使您的问题与泛型相关,当您有两个非泛型的相同类型的参数时,Mockito也会采取相同的方式。
我假设您有一个构造函数,它接受两个Supplier。所以你可以在测试之前调用它。
@BeforeEach
public void setup() {
service = new SomeService(stringSupplier, longSupplier);
}如果不能访问构造函数(例如,它有包作用域),则需要使用反射调用它,并将可访问属性设置为true
@BeforeEach
public void setup() throws Exception {
Constructor<SomeService> constructor = SomeService.class.getConstructor(Supplier.class, Supplier.class);
constructor.setAccessible(true);
service = constructor.newInstance(stringSupplier, longSupplier);
}如果要删除PS,请确保模拟是以服务longTimeSupplier vs. longSupplier中的字段命名的,或者使用@Mock(name = "longTimeSupplier")。
https://stackoverflow.com/questions/69079787
复制相似问题