【问题标题】:Mock method which is called inside another method在另一个方法中调用的模拟方法
【发布时间】:2018-09-25 16:23:31
【问题描述】:

我正在尝试使用 Powermock 模拟对数据库的调用。下面是我们的代码的示例:

public class WrapperClass {
    public static SearchUtil searchUtil = new SearchUtil();
}

public class SearchUtil {
    public Record searchForThing(String thing) {
        // Makes a call to a database and returns a record
    }
}

public class TestableClass {
    public void runMethod() {
        // When this is called, it returns null, however based on the debugger, WrapperClass.searchUtil is a mocked object
        WrapperClass.searchUtil.searchForThing("thing");
    }
}

@PrepareForTest(WrapperClass.class)
@PowerMockIgnore({"javax.management.*", "javax.xml.parsers.*", "com.sun.org.apache.xerces.internal.jaxp.*", "ch.qos.logback.*", "org.slf4j.*", "org.apache.xerces.*", "javax.xml.*", "org.xml.sax.*", "org.w3c.dom.*"})
@RunWith(PowerMockRunner.class)
public class MyTest {
    @Test
    public void runMyTest() {
        SearchUtil searchUtil = PowerMockito.mock(SearchUtil.class);
        PowerMockito.mockStatic(WrapperClass.class);
        Whitebox.setInternalState(WrapperClass.class, "searchUtil", searchUtil);
        PowerMockito.doReturn(new SearchRecord()).when(WrapperClass.searchUtil).searchForThing("thing");

        // When the below call is made, a new SearchRecord is returned and is not null
        WrapperClass.searchUtil.searchForThing("thing");

        // Calling the method that calls the searchForThing method, when searchForThing is called inside runMethod, it returns null
        new TestableClass().runMethod();
    }
 }

我知道静态变量等绝对不是最佳实践,但现在让我们假装我无法更改它。当在测试中调用被模拟的调用时,它会按预期返回一个新的SearchRecord。当它在runMethod 中调用时,它返回 null 但是根据我的调试器,searchUtil 对象 is 是模拟对象。为什么嵌套调用存根方法时会出现这种行为?

【问题讨论】:

  • 上述代码中indexUtil在哪里定义?
  • 复制/粘贴 snafu,我将其更改为 searchUtil
  • SearchUtil 也没有在包装类中初始化,因为被调用的成员是实例方法?
  • 也只是翻译问题,我会解决的。
  • 明白,但是像这样的小事让我们很难正确隔离问题。

标签: java unit-testing mockito powermockito


【解决方案1】:

查看以下内容,其行为应符合预期。

@PowerMockIgnore({"javax.management.*", "javax.xml.parsers.*", "com.sun.org.apache.xerces.internal.jaxp.*", "ch.qos.logback.*", "org.slf4j.*", "org.apache.xerces.*", "javax.xml.*", "org.xml.sax.*", "org.w3c.dom.*"})
@RunWith(PowerMockRunner.class)
@PrepareForTest(WrapperClass.class, TestableClass.class)
public class MyTest {
    @Test
    public void runMyTest() {
        //Arrange 
        Record expected = new SearchRecord();
        String arg = "thing";
        SearchUtil searchUtil = PowerMockito.mock(SearchUtil.class);
        when(searchUtil.searchForThing(arg)).thenReturn(expected);

        // mock all the static members in WrapperClass class
        PowerMockito.mockStatic(WrapperClass.class);
        // use Mockito to set up your expectation
        when(WrapperClass.searchUtil).thenReturn(searchUtil);

        TestableClass subject = new TestableClass();

        //Act
        subject.runMethod();

        //Assert
        //...
    }
 }

注意测试的流程。

我还建议确保测试中使用的参数与执行方法传递的参数匹配,因为如果不匹配,那么由于参数/参数不匹配,它也会返回 null .

否则你需要放松参数匹配器

//...

when(searchUtil.searchForThing(any(String.class))).thenReturn(expected);

//...

您还可以查看the powermock-mockito docs here 以更好地了解如何使用该框架。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 2022-10-24
    相关资源
    最近更新 更多