Mock Instance<Class<?>> 在 Junit 中使用 Inject&Any 进行注释



在我的javaee项目中有一个接口:

public interface SomeInterface{...}

和多种实现:

@Stateless(name = "ImplementationA")
public class ImplementationA implements SomeInterface{...}
@Stateless(name = "ImplementationB")
public class ImplementationB implements SomeInterface{...}

为了访问所有实现,我在另一个类中有以下内容:

@Singelton
public class AnotherClass{
@Inject
@Any
private Instance<SomeInterface> impls;
public SomeInterface someMethod(){
for(SomeInterface imp : impls){
if(imp.oneMethod()){
return imp;
}
}
return null;
}
}

如果我想为这个"另一个类"做单元测试,我该如何模拟

Instance<SomeInterface> impls

田?

@Spy,尝试@Mock无法从 Mockito 内部正确模拟"impls",当测试运行时,"impls"始终为空。

单元测试本身如下所示:

@RunWith(MockitoJUnitRunner.class)
public class SomeTestClass {
@InjectMocks
AnotherClass anotherClass;
@Spy // Here I tried @Mock as well
private Instance<SomeInterface> impls;
@Test
public void TestSomeMethod(){
Assert.assertTrue( anotherClass.someMethod() == null ); // <- NullPointerException here, which indicates the impls is null instead of anotherClass.
}
}

必须在该"OtherClass"中添加另一个方法来接受实例 impls 的实例,该实例是在单元测试中创建的,该实例有效,但丑陋的是,必须仅出于单元测试的目的添加另一个不相关的方法。

知道进行单元测试的正确方法是什么样子的吗?

Mockito和Junit版本:

group: 'junit', name: 'junit', version: '4.12'
group: 'org.mockito', name: 'mockito-core', version:'2.12.0'

提前谢谢。

你可以尝试做什么:

  1. 如果需要,请添加一些期望。如果它是间谍,您可能需要此impls.xxxx()来调用真实方法(猜测这是默认行为(。

  2. 也许也先尝试初始化模拟:

    @RunWith(MockitoJUnitRunner.class)
    public class SomeTestClass {
    @InjectMocks
    AnotherClass anotherClass;
    @Spy  
    private Instance<SomeInterface> impls;
    // init here
    @Before 
    public void initMocks() {
    MockitoAnnotations.initMocks(this);
    }
    @Test
    public void TestSomeMethod(){
    anotherClass.someMethod(); // <- NullPointerException here, which indicates the impls is null instead of anotherClass.
    }
    }
    

此 init 调用需要位于基类或测试运行程序中的某个位置。

这很奇怪,它没有它就不起作用,我想如果你使用MockitoJUnitRunner,它应该可以工作。

上级:


已经很长时间了,但我可以看到有一些新的评论,所以提供额外的意见。

这是有效的测试。

// ImplementationA.oneMethod simply returns TRUE in my case
// ImplementationB.oneMethod simply returns FALSE
@RunWith(MockitoJUnitRunner.class)
public class AnotherClassTest {
@Spy // can be Mock
Instance<SomeInterface> impls;
@InjectMocks
AnotherClass classUnderTest;
@Mock
Iterator<SomeInterface> iterator; // why need it - check below :)
@Test
public void someMethod() {
when(impls.iterator()).thenReturn(iterator);
when(iterator.hasNext()).thenReturn(true).thenReturn(false);
when(iterator.next()).thenReturn(new ImplementationA());

SomeInterface res = classUnderTest.someMethod();
System.out.println("done");
}
}

问题出在哪里?这里:

public SomeInterface someMethod() {

// explanation: For-Each uses iterator
// if we do not mock Instance<SomeInterface> impls properly
// impls.iterator() under the hood will return NULL -> NPE
for (SomeInterface imp : impls) {
if (imp.oneMethod()) {
return imp;
}
}
return null;
}

这就是为什么在我的测试中我还创建了虚拟迭代器(Mock(。我还需要提供一些期望来使其工作,它们是:

when(impls.iterator()).thenReturn(iterator); // returns my mock
when(iterator.hasNext()).thenReturn(true).thenReturn(false);
when(iterator.next()).thenReturn(new ImplementationA());

希望清楚:)这样做可以使每个工作正常并返回ImplementationA

快乐的黑客:)

最新更新