java - 如何在构造函数内模拟实例?

标签 java junit mocking mockito junit5

我有课

public class MockSampleUser {

    private Address address = null;

    public MockSampleUser(){
        address = new Address();
    }

    public String getAddress(){
        return address.getAddress();
    }

    class Address {
        public String getAddress(){
            return "Address";
        }
    }

}

单元测试:

import static org.junit.Assert.*;
import org.junit.Test;
import static org.mockito.Mockito.*;

public class MockSampleUserTest {

    @Test
    public void MockSampleUser(){

        MockSampleUser.Address address = mock(MockSampleUser.Address.class);
        MockSampleUser mockSampleUser = spy(MockSampleUser.class);

        when(address.getAddress()).thenReturn("New Address");
        String add = mockSampleUser.getAddress();
        assertEquals("New Address", add);

        add = mockSampleUser.getAddress();
        assertEquals("Address", add);
    }
}

我想编写一个测试,当我调用 MockSampleUser 类的 getAddress 时,它将返回“New Address”。 我想写一个测试,当我调用 MockSampleUser 类的 getAddress 时,它会返回“New Address”。

最佳答案

模拟旨在模拟被测对象的依赖关系,而不是模拟实现细节。
实际上 address 不是客户端可以设置的依赖项,因此您无法使用 Mockito 来模拟它。
您应该做的是重载构造函数/更改实际构造函数以接受 Address 参数,或者如果依赖项是可变的,则为此字段提供 setter 。
例如使用构造函数:

public MockSampleUser(){
    address = new Address();
}

public MockSampleUser(Address){
    this.address = address;
}

例如使用 setter :

public void setAddress(Address){
    this.address = address;
}

请注意,关于您的单元测试,您希望 getAddress() 在多次调用它时返回不同的内容:

String add = mockSampleUser.getAddress();
assertEquals("New Address", add);

add = mockSampleUser.getAddress();
assertEquals("Address", add);

这是没有意义的,因为它引用了同一个对象,并且它的状态在两个断言之间没有改变。

如果您不允许地址依赖项可变,那么您的测试应该看起来像( spy 在这里无能为力,并且在大多数情况下都是正确的):

@Test
public void MockSampleUser(){
    MockSampleUser.Address address = mock(MockSampleUser.Address.class);
    MockSampleUser mockSampleUser = new MockSampleUser(address);
    when(address.getAddress()).thenReturn("New Address");

    String add = mockSampleUser.getAddress();
    assertEquals("New Address", add);
    // or better, use the address object itself as expected
    assertEquals(address.getAddress(), add);
}

如果您允许地址依赖项是可变的,那么应该优先使用 setter,您可以在其中断言被测对象的之前/之后状态:

@Test
public void MockSampleUser(){
    MockSampleUser mockSampleUser = new MockSampleUser();
    // before setting the address
    assertEquals("Address", mockSampleUser.getAddress());

    // after setting the address
    MockSampleUser.Address address = mock(MockSampleUser.Address.class);
    mockSampleUser.setAddress(address);
    when(address.getAddress()).thenReturn("New Address");
    String add = mockSampleUser.getAddress();
    assertEquals("New Address", add);
    // or better, use the address object itself as expected
    assertEquals(address.getAddress(), add);
}

关于java - 如何在构造函数内模拟实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50863363/

相关文章:

java - 如何从 String 加载 RSA 公钥以在 Java 中进行签名验证?

java - 帮助自定义迭代器

java - 服务内部的测试方法

Url 模拟测试中出现 java.lang.NullPointerException

python - Python 2.7 中的模拟 bool __bool__ 协议(protocol)方法

Java RSA 加密 - 解密 .NET

java - Apache Commons Codec Base64 是 sun.misc.BASE64 的直接替代品吗?

git - Jenkins 找不到 JUnit (Netbeans+ Git + Ant + JUnit + Jenkins)

java - @Autowired BeanCreationException 与 JUnit

java - 如何在 Junit 中使用 @InjectMocks 和 @Autowired 注释