Java 在单元测试时,如何使用Mockito模拟来自另一个类的响应
我有一个方法要测试,它调用另一个类来获取一些信息:Java 在单元测试时,如何使用Mockito模拟来自另一个类的响应,java,mockito,Java,Mockito,我有一个方法要测试,它调用另一个类来获取一些信息: public ClassToTest { public void methodToTest() { AnotherClass ac = Factory.getInstance(); ResponseObj response = ac.anotherMethod(); } } 另一个类是另一个JAR的一部分,我想模拟来自它的响应,使之成为特定的mock ResponseObj响应 如何使用Moc
public ClassToTest {
public void methodToTest() {
AnotherClass ac = Factory.getInstance();
ResponseObj response = ac.anotherMethod();
}
}
另一个类是另一个JAR的一部分,我想模拟来自它的响应,使之成为特定的mock ResponseObj响应
如何使用Mockito实现这一点?首先需要使类可测试。这意味着您需要从methodToTest to instance字段中提取对象创建另一个类ac=Factory.getInstance,或者可能是单独的方法来模拟它,或者更好的方法是在类之外创建对象并通过构造函数传递它。因此,被测试的类应该如下所示:
public class ClassToTest {
private AnotherClass ac;
public ClassToTest(AnotherClass ac) {
this.ac = ac;
}
public void methodToTest() {
ResponseObj response = ac.anotherMethod();
response.smth();
}
}
然后,您需要将另一个类和ResponseObj声明为测试类中的字段,并将它们初始化为mock
AnotherClass ac = Mockito.mock(AnotherClass.class);
ResponseObj responseMock = Mockito.mock(ResponseObj.class);
之后,您可以模拟方法调用:
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
最后,您的测试类应该如下所示:
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = new ClassToTest(anotherClassMock);
@Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
若您不能更改ClassToTest的公共API,您可以使用Mockito spy和protected方法的方法
public class ClassToTest {
public void methodToTest() {
AnotherClass ac = constructAnotherClassObj();
ResponseObj response = ac.anotherMethod();
response.smth();
}
protected AnotherClass constructAnotherClassObj() {
return Factory.getInstance();
}
}
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = spy(new ClassToTest());
@Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
when(classToTest.constructAnotherClassObj()).thenReturn(anotherClassMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
首先,您需要使您的类可测试。这意味着您需要从methodToTest to instance字段中提取对象创建另一个类ac=Factory.getInstance,或者可能是单独的方法来模拟它,或者更好的方法是在类之外创建对象并通过构造函数传递它。因此,被测试的类应该如下所示:
public class ClassToTest {
private AnotherClass ac;
public ClassToTest(AnotherClass ac) {
this.ac = ac;
}
public void methodToTest() {
ResponseObj response = ac.anotherMethod();
response.smth();
}
}
然后,您需要将另一个类和ResponseObj声明为测试类中的字段,并将它们初始化为mock
AnotherClass ac = Mockito.mock(AnotherClass.class);
ResponseObj responseMock = Mockito.mock(ResponseObj.class);
之后,您可以模拟方法调用:
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
最后,您的测试类应该如下所示:
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = new ClassToTest(anotherClassMock);
@Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
若您不能更改ClassToTest的公共API,您可以使用Mockito spy和protected方法的方法
public class ClassToTest {
public void methodToTest() {
AnotherClass ac = constructAnotherClassObj();
ResponseObj response = ac.anotherMethod();
response.smth();
}
protected AnotherClass constructAnotherClassObj() {
return Factory.getInstance();
}
}
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = spy(new ClassToTest());
@Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
when(classToTest.constructAnotherClassObj()).thenReturn(anotherClassMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
尽管@arsen_adzhiametov的话是正确的,而且达到了标准,但我还是想谈谈我是如何做到这一点的
在本例中,我在模仿HomeClient的价值,它在内部是一个WebClient,为某些价值调用另一个服务
java请给它起个更好的名字
...
import org.mockito.Mockito;
...
class TestClass {
HomeClient mockHomeClient;
@BeforeEach
void setup() {
mockHomeClient = Mockito.mock(HomeClient.class);
// Axon specific test code. Can ignore if not using Axon.
fixture = new AggregateTestFixture<>(SomeAgreegate.class);
fixture.registerInjectableResource(mockHomeClient);
}
@Test
void testOpenOperation() throws HomeClientException {
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(2);
// Do what you will with your code and call the method which you want to test
// Mockito will mock the `HomeClient` in this case and `getXYZ` will return `2`
// You can also change the mock response any time in the same function
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(-100);
// Or specify different results on mock when different values are provided
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(1);
Mockito.when(mockHomeClient.getXYZ("foo")).thenReturn(100);
Mockito.when(mockHomeClient.getXYZ("bar")).thenReturn(0);
}
}
尽管@arsen_adzhiametov的话是正确的,而且达到了标准,但我还是想谈谈我是如何做到这一点的
在本例中,我在模仿HomeClient的价值,它在内部是一个WebClient,为某些价值调用另一个服务
java请给它起个更好的名字
...
import org.mockito.Mockito;
...
class TestClass {
HomeClient mockHomeClient;
@BeforeEach
void setup() {
mockHomeClient = Mockito.mock(HomeClient.class);
// Axon specific test code. Can ignore if not using Axon.
fixture = new AggregateTestFixture<>(SomeAgreegate.class);
fixture.registerInjectableResource(mockHomeClient);
}
@Test
void testOpenOperation() throws HomeClientException {
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(2);
// Do what you will with your code and call the method which you want to test
// Mockito will mock the `HomeClient` in this case and `getXYZ` will return `2`
// You can also change the mock response any time in the same function
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(-100);
// Or specify different results on mock when different values are provided
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(1);
Mockito.when(mockHomeClient.getXYZ("foo")).thenReturn(100);
Mockito.when(mockHomeClient.getXYZ("bar")).thenReturn(0);
}
}
可能会给你一些想法。@DawoodibnKareem这是一篇好文章+1可能会给你一些想法。@DawoodibnKareem这是一篇好文章+1如果我可以包含构造函数,这个解决方案将非常有效。你能建议一个解决方案,在不改变ClassToTested结构的情况下实现同样的效果吗?我对此有一些限制。您可能希望应用的第三个选项是PowerMock,它允许模拟静态方法调用,如Factory.getInstanceHanks以获取建议。我尝试了方法2,创建了一个受保护的方法和间谍。在这种情况下,responseMock总是为null。这是预期的吗?这里不应该有任何异常,除非您模拟的方法中没有任何异常。请记住,当您模拟方法调用时,如-when…,然后返回…-您的方法实际上已调用,只返回被mock替换的对象。有些情况下,当你根本不希望你的方法被执行时,所以你可以使用另一种存根方法-doReturn…当…分享更多关于你得到的异常的细节时。如果我可以包含构造函数,这个解决方案会非常好用。你能建议一个解决方案,在不改变ClassToTested结构的情况下实现同样的效果吗?我对此有一些限制。您可能希望应用的第三个选项是PowerMock,它允许模拟静态方法调用,如Factory.getInstanceHanks以获取建议。我尝试了方法2,创建了一个受保护的方法和间谍。在这种情况下,responseMock总是为null。这是预期的吗?这里不应该有任何异常,除非您模拟的方法中没有任何异常。请记住,当您模拟方法调用时,如-when…,然后返回…-您的方法实际上已调用,只返回被mock替换的对象。有些情况下,当您根本不希望执行您的方法时,所以您可以使用另一种存根方法-doReturn…当…共享有关异常的更多详细信息时。