Mockito:从mocked Class调用方法时的java.lang.NullPointerException

Ste*_*eSt 1 java nullpointerexception mockito

我正在使用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();
}
}
Run Code Online (Sandbox Code Playgroud)

这是类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*/
}
}
Run Code Online (Sandbox Code Playgroud)

这是ResourceC类

public class ResourceC {
public String callFuncA() {
    /*Calling callFuncB and doing some other stuff*/
    return testString;
}

public List<B> callFuncB() {
/*return a List*/
}
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是在类ResourceB中的方法callFuncC时行

String test2 = c.callFuncA();
Run Code Online (Sandbox Code Playgroud)

叫做我得到一个NullPointerException

知道为什么会发生这种情况吗?

Bri*_*ice 6

您的代码中存在几个问题,第一个问题是您正在模拟要测试的类,这样做只会测试模拟,ResourceB或者您必须存根代码并强制选择的方法来调用实际代码(thenCallRealMethod).主要的想法是永远不要嘲笑你正在测试的课程.

这也是你有NPE的原因,因为mock不需要内部字段实例.因为它不应该.

这是一个正确的方法,可能有变化,但一个是最直接的.所以基本上你想测试之间的相互作用ResourceBResourceC,因为这是一个单元测试ResourceB,你会想嘲笑ResourceC.事情是每个实例的模拟,所以你必须通过模拟的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

  // ...
}
Run Code Online (Sandbox Code Playgroud)

在测试中你会这样写:

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");
  }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一下,这里有几件事要补充:

  • 当您使用JUnit 4.x时,我正在使用更有意义/描述性的方法名称.
  • 我正在使用行为驱动开发关键字(给定,何时,然后)来帮助驱动测试场景.
  • 我也使用AssertJ lib来编写有意义的断言.