如何模拟已经在要测试的类的代码中实例化的对象并为其编写存根?

时间:2017-04-24 18:59:43

标签: java unit-testing junit mockito

我需要测试的类看起来有点类似于此。我不是在这里写实际课程。

public class Client {

private String country;
private ConnectionImpl conn;

public Client (String country){
    this.country = country;
}

private ConnectionImpl createConnection() {
  SetConnectionImpl impl = new SetConnectionImpl() {
    public String getFirstName() {
      return "Some value";
    }
    public String getLastName() {
      return "Some value";
    }
    public String getAddress() {
      return "Some value";
    }
    public String getPhoneNumber() {
      return "Some value";
    }};
  return new ConnectionImpl("", "", "", "", impl);
}

public String letsDoSomeWork(String requestObject) {
  final ConnectionImpl impl = createConnection();
  String letsHaveSomeResponse = 
  impl.methodTobeStubbed(requestObject);
  return letsHaveSomeResponse;
}
}

现在我写的测试类看起来像这样。我正在使用mockito来编写存根。

@Runwith(MockitoJunitRunner.class)
public class ClientTest {
@Mock
ConnectionImpl impl;

private Client client;
@Before()
public void initialize() {
client = new Client("India");
}

@Test
public void testLetsDoSomework_ShouldReturnString() {
String request = "request";
when(impl.methodTobeStubbed(request)).thenReturn("Response");
String letsHaveSomeResponse = client.letsDoSomeWork(request);
//Now I will make Assertions
}

}

不幸的是,这个存根不起作用,我的假设是,因为要测试的类是在内部创建一个" impl"对象,我在这里创建的模拟对象没有被考虑。所以最后代码进入了" impl"不应该的课程。

when(impl.methodTobeStubbed(request)).thenReturn("Response");

2 个答案:

答案 0 :(得分:0)

您可以让createConnection方法返回您的模拟连接。

首先,将方法更改为protected

protected ConnectionImpl createConnection() {
    .... // same code
}

如果该方法是私有的,则无法在测试中模拟它。

然后,在您的测试中,使用Client方法使用Mockito.spy对象进行间谍:

@Before()
public void initialize() {
    client = Mockito.spy(new Client("India"));

    // letsDoSomeWork method will be called (instead of a mocked version)
    when(client.letsDoSomeWork(anyString())).thenCallRealMethod();

    // createConnection returns your mocked impl object (it doesn't compile if createConnection method is private)
    when(client.createConnection()).thenReturn(impl);
}

然后,当您致电letsDoSomeWork时,它会调用Client课程中的真实方法。因此,createConnection将被调用 - 并且当它被模拟时,它将返回模拟的impl对象。

注意:请确保ClientTest类与Client类位于同一个包中,以便通过测试使createConnection可见(即使它们位于不同的源文件夹中 - 比如src/mainsrc/test,假设您正在使用maven或类似名称 - 包名称必须相同)

另一种方法是为连接创建一个setter方法:

public class Client {

    private String country;

    private ConnectionImpl conn;

    public Client(String country) {
        this.country = country;
    }

    // create setter method for connection    
    public void setConn(ConnectionImpl conn) {
        this.conn = conn;
    }

    public String letsDoSomeWork(String requestObject) {
        // no need to createConnection
        String letsHaveSomeResponse = 
        this.conn.methodTobeStubbed(requestObject);
        return letsHaveSomeResponse;
    }
}

所以你的测试就像:

@RunWith(MockitoJUnitRunner.class)
public class ClientTest {

    @Mock
    MyConn impl;

    private Client client;

    @Before
    public void initialize() {
        client = new Client("India");
        client.setConn(impl);
    }

    @Test
    public void testLetsDoSomework_ShouldReturnString() {
        String request = "request";
        when(impl.methodTobeStubbed(request)).thenReturn("Response");

        String letsHaveSomeResponse = client.letsDoSomeWork(request);

        // do assertions
    }
}

甚至更好,制作一个接收连接的构造函数:

public Client(String country, ConnectionImpl conn) {
    this.country = country;
    this.conn = conn;
}

在测试课程中:

@Before
public void initialize() {
    client = new Client("India", impl);
}

答案 1 :(得分:0)

我让测试用例发挥作用。这就是我所做的。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Client.class)
public class ClientTest {

@Mock
ConnectionImpl impl;

private Client client;
@Before()
public void initialize() {
    client = PowerMockito.spy(new Client("India"));
    doReturn(impl).when(client, "createConnection");
}

@Test
public void testLetsDoSomework_ShouldReturnString() {
    String request = "request";
    when(impl.methodTobeStubbed(request)).thenReturn("Response");
    String letsHaveSomeResponse = client.letsDoSomeWork(request);
//Now I will make Assertions
}