【问题标题】:Mock inner methods using Mockito使用 Mockito 模拟内部方法
【发布时间】:2016-08-15 18:38:08
【问题描述】:

我是 Mockito 的新手。 我正在尝试通过模拟数据库交互来为服务编写 jnuit:

我有以下课程(仅代表实际课程)

public class TestService{

    public Response getTestList(String type){
        list = getListbyType(type);

        return response.entity(list);
    }

    private List getListbyType(String type){
          ...
          ..
          TestDAO testdao = new Testdao(sqlconn);
          list = testdao.getListfromDB(type)
          return list;
   }
}

我的测试课是这样的

public class TestServiceTest{

    @InjectMocks
    private TestService testService = new TestService();
    @Test
    public void getTestListTest(){

        List testlist = new List();
        tetslist.add("test1");

        TestDAO testdaomock = mock(TestDAO);
        when(testdaomock.getListfromDB("test")).thenreturn(list);

        list = testService.getTestList(test);
    }
}

但是当我运行这个测试时,它仍然调用实际的 DB 调用并从 db 中检索值而不是模拟值,我应该模拟 sql 连接和非默认构造函数吗?我一无所知。

-- 更新

正如人们所建议的,我将 DAO 实例化移至我的服务构造函数并使用了 Spy,但仍然调用了我的实际 DB 调用而不是模拟调用。

【问题讨论】:

  • testdaomock.getListfromDB("test") 不应编译,因为 private List getListbyType(String type) 是私有的。它是如何编译的?
  • getListbyType(String type) 是私有的,但是 testdaomock.getList‌​fromDB("test") 是在公共的 DAO 类中
  • @RunWith(MockitoJUnitRunner.class)
  • 这个测试的问题实际上是被测代码的糟糕设计:不应在对“getter”的调用中实例化任何 DAO。该 DAO 实例的唯一位置是一个字段,在构造时实例化或在需要时延迟实例化(测试将执行前者)。

标签: java junit mockito


【解决方案1】:

您的问题在于以下陈述:

TestDAO testdao = new Testdao(sqlconn);

你从 mock() 得到的 TestDAO 的实例不是 testdao.getListfromDB(type) 后面 new 使用的实例

为了成功模拟,您需要在整个过程中应用依赖反转。这意味着new 只能出现在您不打算测试的类中,例如简单的工厂或 Spring 配置文件。

[更新]

如果不能选择合适的 IOC,你可以引入一个分配 DAO 的方法,然后 spy() 它。该方法必须是包私有的。这被描述为here

另一种选择是添加一个包私有构造函数,以testdao 作为参数,并用该构造函数的形式表达您的默认构造函数。

【讨论】:

  • 有道理,但我现在不能介绍 IOC,有没有办法模拟这个参数化构造函数而不是默认构造函数?
  • 您可以使用 PowerMock,但您需要使用单独的junit runner,请参阅github.com/jayway/powermock/wiki/…
  • 您可以尝试将TestDAO 注入TestService,方法是在getTestList 方法中传递对TestDAO 实例的引用。另一种方法是在TestService 中添加TestDAO 属性,设置默认值,例如在默认构造函数中,然后在TestService 中添加一个设置器,它将设置TestDAO 属性。然后你可以在你的测试中使用这个 setter 来传递一个 TestDAO 模拟。
【解决方案2】:

如果您无法更改 TestService 类(遗留代码),则可以使用 PowerMockito (https://github.com/jayway/powermock) 模拟新实例。这使用允许字节码操作的自己的 junit 运行器 (PowerMockRunner)。

这里是您的代码示例:

import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
public class TestServiceTest {

   @Mock
   TestDAO testDaoMock;

   @Test
   public void test() throws Exception {
    List<String> testlist = new ArrayList<>();
    testlist.add("test1");
    when(testDaoMock.getListfromDB(anyString())).thenReturn(testlist);
    PowerMockito.whenNew(TestDAO.class).withAnyArguments().thenReturn(testDaoMock);
    TestService testService = new TestService();
    Response actualResponse = testService.getTestList("testType");
    assertEquals(expectedResponse, actualResponse);
    }
}

您需要将 powermock-api-mockito 和 powermock-module-junit4 添加到您的依赖项中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 2014-06-07
    • 2015-12-13
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多