我正在使用mockito为应用程序编写一些单元测试,该应用程序已经通过集成测试进行了测试,但我们还需要开发单元测试。
这是测试代码:
public class TestResourceB {
@Mock
ResourceB b;
@Mock
ResourceC c;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
TestObjects.InitializeObjects();
}
@Test
public void testMethodResourceA() {
when(b.callFuncA()).thenCallRealMethod();
when(b.callFuncB()).thenReturn(TestObjects.mockedListA);
when(b.callFuncC((B)anyVararg())).thenCallRealMethod();
when(c.callFuncB()).thenReturn(TestObjects.mockedListB);
when(c.callFuncA()).thenCallRealMethod
String output = b.callFuncA();
}
}
这是ResourceB 类
public class ResourceB {
ResourceC c = new ResourceC();
public String callFuncA(){
/*Calling callFuncB and doing some other stuff*/
String test = callFuncC(arg1);
}
public List<A> callFuncB() {
/*returns the mocked list A*/
}
public String callFuncC(B arg1) {
String test2 = c.callFuncA(); // It crashes here
/*doing some other stuff*/
}
}
这是ResourceC 类
public class ResourceC {
public String callFuncA() {
/*Calling callFuncB and doing some other stuff*/
return testString;
}
public List<B> callFuncB() {
/*return a List*/
}
}
我遇到的问题是,在ResourceB类中的方法callFuncC中,当行
String test2 = c.callFuncA();
被调用我得到一个NullPointerException
知道为什么会发生这种事吗?
您的代码中有几个问题,第一个问题是您正在模拟要测试的类,这样您将只测试ResourceB
的模拟,否则您将不得不截断代码并强制所选方法调用实际代码(thenCallRealMethod
)。其主要思想是永远不要模拟您正在测试的类。
这也是为什么您有一个NPE,因为mock不需要内部字段实例。因为它不需要。
这里有一个正确的方法,可能会有变化,但那是最直接的。所以基本上,你想测试ResourceB
和ResourceC
之间的交互,因为这是ResourceB
的单元测试,你想模拟ResourceC
。问题是每个实例都有mock,所以必须将mock传递给ResourceB
。
它可以通过构造函数注入来注入,然后需要修改ResourceB
:
public class ResourceB {
ResourceC c;
public ResourceB() { c = new resourceC(); } // normal behavior
@VisibleForTesting // guava annotation (in, order to expalain why there is this constructor)
ResourceB(ResourceC c_override) { c = c_override; } // constructor for the test, note the package visibility
// ...
}
在测试中,你会这样写:
public class TestResourceB {
ResourceB tested_b;
@Mock ResourceC mocked_c;
@Before
public void init_tested_and_mocks() {
MockitoAnnotations.initMocks(this);
tested_b = new ResourceB(mocked_)
}
@Test
public void ensure_result_from_ResourceC_is_returned() {
// given
when(mocked_c.callFuncA()).thenReturn("result that should be returned");
// when
String output = tested_b.callFuncA();
// then
assertThat(output).isEqualTo("result that should be returned");
}
}
顺便说一下,这里有一些需要添加的内容:
- 当您使用JUnit4.x时,我将使用更有意义/描述性的方法名称
- 我正在使用行为驱动开发关键字(给定,当时,then)来帮助驱动测试场景
- 此外,我还使用AssertJ lib来编写有意义的断言