java Mockito:从模拟类调用方法时出现java.lang.NullPointerException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17652945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 14:32:31  来源:igfitidea点击:

Mockito : java.lang.NullPointerException when calling method from mocked Class

javanullpointerexceptionmockito

提问by SteveSt

I am using mockito to write some unit tests for an application which is already tested with integration testing but we need also to develop unit tests.

我正在使用 mockito 为已经通过集成测试进行测试的应用程序编写一些单元测试,但我们还需要开发单元测试。

This is the code for the testing :

这是测试的代码:

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();
}
}

This is the class ResourceB

这是 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*/
}
}

This is the class ResourceC

这是 ResourceC 类

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

public List<B> callFuncB() {
/*return a List*/
}
}

The problem that I have is that in method callFuncC in class ResourceB when the line

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

String test2 = c.callFuncA();

is called I get a NullPointerException

被称为我得到一个 NullPointerException

Any idea why this could be happening ?

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

回答by Brice

There is several issues in your code, the first one being that you are mocking the class you want to test, doing that you will only test the mock of ResourceBor you'll have to stub the code and force chosen method to call real code (thenCallRealMethod). The main idea is to nevermock the class you are testing.

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

That is also why you have an NPE, because a mock don't need internal fields instance. As it should'nt need to.

这也是您拥有 NPE 的原因,因为模拟不需要内部字段实例。因为它不应该需要。

Here's a correct way, there might be variations but that one is the most straightforward. So basically you'd want to test the interactions between ResourceBand ResourceC, as this is a unit test of ResourceByou'd want to mock ResourceC. The thing is mocks are per instance so you have to pass the mocked one to ResourceB.

这是一个正确的方法,可能会有变化,但那个是最直接的。所以基本上你想测试之间的相互作用ResourceBResourceC,因为这是一个单元测试ResourceB,你会想嘲笑ResourceC。事情是模拟是每个实例,所以你必须将模拟的一个传递给ResourceB.

It can be injected via constructor injection, you then need to modify the 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

  // ...
}

And in the test you'll write it this way :

在测试中你会这样写:

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");
  }
}

By the way here's a few things to add :

顺便说一下,这里有一些要添加的内容:

  • As you are using JUnit 4.x, I'm using more meaningful/descriptive method names.
  • I'm using the Behavior Driven Developmentkeywords (given, when, then) to help drive the test scenario.
  • Also I use AssertJlib to write meaningful assertions.
  • 当您使用 JUnit 4.x 时,我使用更有意义/描述性的方法名称。
  • 我正在使用行为驱动开发关键字(givenwhenthen)来帮助驱动测试场景。
  • 我还使用AssertJlib 来编写有意义的断言。