【问题标题】:Cannot instantiate mock objects using InjectMocks-Mockito无法使用 InjectMocks-Mockito 实例化模拟对象
【发布时间】:2015-12-23 18:24:08
【问题描述】:

我也是 TDD 和 mockito 的新手,我正在尝试将 mock 注入到一个类中以执行单元测试,该类根据一些验证在方法内实例化它的依赖项,我收到了一个错误

测试类/方法

//Its interface 
public interface UserService {

    public Debt getCustomerDebt(String id);
}

//validator method

public static boolean isValidId(String id){
    if(id != null && !id.isEmpty() && !id.trim().equals("")){
        return true;
    }
    return false;
}

public class UserServiceImpl implements UserService {

    private Repository repo;
    private WSDLCustomerDebt wsdlCostumerDebt;

    public static final int USER_EXIST = 1;
    public static final int USER_DOESNOT_EXIST = 0;

    public UserServiceImpl(){

    }

    public Debt getCustomerDebt(String id) {

        if(ValidatorHelper.isValidId(id)){
            repo = new RepositoryImpl();
            int exist = repo.getCustomer(id);
            if(exist==USER_EXIST){
                wsdlCostumerDebt = new WSDLCustomerDebtImpl();
                List<Date> meses = wsdlCostumerDebt.obtenerMeses(id);
                if(meses.size()>0){
                    int totalDebt = 0;
                    for (Date mes : meses){
                        totalDebt += wsdlCostumerDebt.obtenerDeuda(mes, id);
                    }

                    return new Debt(id, BigDecimal.valueOf(totalDebt));

                }else{
                    return new Debt(id, BigDecimal.valueOf(0));
                }
            }
        }
        return null;
    }

}

模拟类存储库实现

public class RepositoryImpl implements Repository {

    public int getCustomer(String id) {
        int y = Integer.valueOf(1);
        return y;
    }

}

wsdl 模拟类

//Interface
public interface WSDLCustomerDebt {

    public List<Date> obtenerMeses(String customerId);

    public Integer obtenerDeuda(Date month, String customerId);

}

public class WSDLCustomerDebtImpl implements WSDLCustomerDebt {

    public List<Date> obtenerMeses(String customerId) {
        return null;
    }

    public Integer obtenerDeuda(Date month, String customerId) {
        Integer y = Integer.valueOf(11);
        return y;
    }
}

域类债务

public class Debt {

    private String id;
    private BigDecimal debt;

    public Debt(String id, BigDecimal debt) {
        super();
        this.id = id;
        this.debt = debt;
    }

    //Getters and setters ....
}

最后测试类

import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

public class UserServiceImplTest {
    @Mock
    private Repository repo;

    @Mock
    private WSDLCustomerDebt wsdlCustomerDebt;

    @InjectMocks
    private UserServiceImpl userService; 

    @Before
    public void init(){
        //repo=Mockito.mock(Repository.class);      
        //when(wsdlcustomer.obtenerDeuda(D, customerId))
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void noExistingCustomer(){
        //Given:
        String id = "123";
        //When:
        Mockito.when(repo.getCustomer(id)).thenReturn(0);
        Debt debt = userService.getCustomerDebt(id);
        Mockito.verify(repo.getCustomer(Mockito.any(String.class))); 
        //Then:
        assertNull(debt);   
    }
}

这是我遇到的错误,我试图避免使用构造函数或任何 getter/setter 并通过参数接收模拟,也许它可能是由虚拟错误引起的,但此时我没有知道我做错了什么,实际上我认为问题的发生是因为模拟类中的 return 语句。我正在使用 mockito 版本 1.9.5 顺便说一句

org.mockito.exceptions.misusing.NotAMockException: 
Argument passed to verify() is of type Integer and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
    verify(mock).someMethod();
    verify(mock, times(10)).someMethod();
    verify(mock, atLeastOnce()).someMethod();
    at com.i2btech.poctest.UserServiceImplTest.noExistingCustomer(UserServiceImplTest.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)

【问题讨论】:

    标签: java unit-testing junit tdd mockito


    【解决方案1】:

    首先,您的服务不使用您正在注入的模拟,因为它会在您调用该方法时创建一个新模拟。 repo 应该是服务构造函数的参数。

    其次,验证模拟方法是否被调用的正确语法不是

    verify(mock.method())
    

    但是

    verify(mock).method()
    

    (正如错误消息中明确指出的那样)。

    所以,这条线

    Mockito.verify(repo.getCustomer(Mockito.any(String.class)))
    

    必须替换为

    Mockito.verify(repo).getCustomer(Mockito.any(String.class))
    

    【讨论】:

    • 该方法的实际实现应该按照我在问题上描述的方式执行,有办法实现吗?初始化模拟而不像参数一样传递它们?在injectmocks的javadoc中提到了一些关于没有指定构造函数的字段注入,这是最好的方法吗?举个例子?
    • 您可以避免将它们作为参数传递给构造函数(尽管这样做会更干净)。关键是该方法不能创建自己的 repo 实例。 repo 必须是服务的一个字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多