【问题标题】:PowerMockito using InjectMocks errorPowerMockito 使用 InjectMocks 错误
【发布时间】:2016-07-20 08:32:30
【问题描述】:

我有一个非常复杂的类来编写 Junit 测试用例。我决定使用 PowerMockito,因为要运行测试的类有一个构造函数初始化。

我的主班是这样的:

public class MainClass extends BaseClass{

MainClass(SomeClass class){
    super(class);
}

public void methodToBeTested(){
some code here
}

..few other methods which I am not going to test.
}

现在我的测试用例是这样写的:

@RunWith(PowerMockRunner.class)
public class TestClass{

@Mock
OtherClassUsedInMainClass mock1;

@Mock
OtherClassUsedInMainClass mock2;

@InjectMocks
MainClass mainClass;

@Before
public void setUp() throws Exception{
    MockitoAnnotations.initMocks(this);
    PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class))
            .thenReturn(mainClass);)
}

@Test
public void testMethodtobeTested(){
    ...I am using the other objects to mock data and test if this method works fine

    mainClass.methodtobeTested();
    \\This method will increment a value. I am just asserting if that value is right. 
    Assert.assertEquals(mainClass.checkCount(),RequiredCount)

}

}

我在运行测试用例时遇到 空指针异常,因为它尝试初始化 ma​​inClass。它不会被嘲笑。我知道我做错了什么。但我就是不知道它是什么。

错误:

org.mockito.exceptions.base.MockitoException: 
Cannot instantiate @InjectMocks field named 'mainClass' of type 'class com.main.MainClass'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null

Caused by: java.lang.NullPointerException
This null pointer exception is thrown from a the constructor of the BaseClass when it tries to initialize another class.

【问题讨论】:

  • 显示BaseClass的构造函数。出现错误
  • 为什么要存根 MainClass?这不是你正在测试的课程吗?
  • @Jens 基类构造函数接受从 mainClass 传递的 someClass 作为参数。它还使用这个 someClass 并用它来初始化一些其他类,这些类也有一个使用 someClass 的构造函数。
  • @AdriaanKoster 你能解释一下吗?
  • 你不应该做类似PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class)).thenReturn(mainClass);)的事情。您应该在没有任何存根行为的情况下针对 MainClass 的普通实例进行测试。

标签: java mockito powermockito


【解决方案1】:

This question解释@Mock@InjectMocks的区别:

@Mock 创建一个模拟。 @InjectMocks 创建该类的一个实例,并将使用 @Mock(或 @Spy)注释创建的模拟注入此实例。

MainClass 构造函数需要一个 SomeClass 参数,但没有任何模拟。

你的代码应该是这样的:

@RunWith(PowerMockRunner.class)
public class TestClass{

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    SomeClass mock1;

    @InjectMocks
    MainClass mainClass;

    @Before
    public void setUp() throws Exception{
    ...

【讨论】:

  • 我这样做了。但是代码仍然进入 BaseClass。当它尝试初始化时,我再次从 BaseClass 获得一个空指针。
  • @ViChU 我希望这是不同的,它与基类使用该模拟的方式有关。可能正在对来自 SomeClass 的方法的返回对象做一些事情。尝试使用@Mock(answer = Answers.RETURNS_DEEP_STUBS)
  • 我试过这个。它仍然从 BaseClass 中抛出一个空值。当 MainClass const 调用 super(someClass) 时,它使用 someClass 调用 BaseClass const。在构造函数内部,创建了一些对象。有些访问 someClass 对象,而有些则在其构造函数中使用 someClass。
  • 很遗憾我不能分享源代码。无论如何,我会尝试其他方法并返回。
  • 如果你用@RunWith(PowerMockRunner.class)注释测试类,你真的需要调用initMocks吗?
【解决方案2】:

引用this answer,即引用@InjectMocks documentation

构造函数注入;选择最大的构造函数,然后使用仅在测试中声明的模拟来解析参数。注意:如果找不到参数,则传递 null。

因此,大概声明一个SomeClass 类型的字段,并对其进行注释@Mock

【讨论】:

    【解决方案3】:

    如果您无法向我们展示实际代码,则很难猜测到底发生了什么。但看起来你的模拟 SomeClass 需要一些存根行为来满足 BaseClass 构造函数。

    例如:

    // the instance of MainClass you run your tests against
    private MainClass instance;
    
    @Mock
    private SomeClass someClass;
    @Mock
    private SomethingElse somethingElse;
    
    @Before
    public void setUp() {
        when(someClass.doSomething()).thenReturn(somethingElse);
        instance = new MainClass(someClass);
    }
    
    @Test
    public void test() {
        // SETUP
        when(somethingElse.doWeirdStuff()).thenThrow(new WeirdException());
    
        // CALL
        instance.performTapDance();
    
        // VERIFY
        assertTrue(instance.isWeird());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多