简体   繁体   English

Mockito没有返回期望值

[英]Mockito not returning expected value

I am using the JUnit and Mockito library to test my application. 我正在使用JUnitMockito库来测试我的应用程序。 The problem is, when I am executed below code, the value is not returning empty list at run time and test is getting failed. 问题是,当我在下面的代码中执行时,该值在运行时未返回空列表,并且测试失败。 Ideally it should be return empty list when getEmployee() get executed 理想情况下,应在执行getEmployee()时返回空列表

public class Check_Test extends TestCase
{
    public void testMyCheck()
    {
        Check checkObj = new Check();
        EmployeeFactory employeeFactoryMock = Mockito.mock(EmployeeFactory.class);
        Mockito.doReturn(Collections.EMPTY_LIST).when(employeeFactoryMock).getEmployee();
        String str = checkObj.myCheck();
        assertEquals("", str);
    }
}

I tried all possibilities best of my knowledge, but I am not able to pass this test case. 我已尽我所能尝试了所有可能的方法,但是我无法通过该测试用例。

The below Check class which having myCheck() method that I need to test for empty... 下面的Check类具有我需要测试的myCheck()方法是否为空...

public class Check
{
    public String myCheck()
    {
        List<Employee> employee = EmployeeFactory.getInstance().getEmployee();
        if (employee.isEmpty())
        {
            return ""; //Line No. 8 returning empty but, control is not coming here
        }
        else
        {
            return "NotEmpty"; // The control is always coming here ????
        }
    }
}

I am eagerly looking forward to support. 我热切希望得到支持。 Can any one please help me out, how to pass this test cases ???. 谁能帮助我,如何通过这个测试用例???。 How to bring the control at line No 8 through Mockito to pass the test case??? 如何使第8行的控件通过Mockito通过测试用例???

Please assume, Below two classes don't have real code, we have only binary file as JAR file, we can not modify the below code.... I am attaching this for our understanding... 请假设,下面的两个类没有真实的代码,我们只有二进制文件作为JAR文件,我们不能修改下面的代码...。

public class EmployeeFactory
{

    private EmployeeFactory()
    {

    }

    public static EmployeeFactory getInstance()
    {
        return EmployeeFactoryHelper.INSTANCE;

    }

    private static class EmployeeFactoryHelper
    {
        public static final EmployeeFactory INSTANCE = new EmployeeFactory();
    }

    private static List<Employee> employees = null;

    static
    {
        employees = Arrays.asList(
                                  new Employee("Manish", "Kumar", true, 60),
                                  new Employee("Siva", "Attla", true, 42),
                                  new Employee("Anand", "Manivel", false, 51),
                                  new Employee("Madhavi", "Govind", true, 45),
                                  new Employee("Janani", "Chidambaram", true, 45),
                                  new Employee("Mannu", "Krishna", false, 39),
                                  new Employee("Karthika", "Hosamane", false, 39)
                          );
    }

    public List<Employee> getEmployee()
    {
        return employees;

    }

}


public class Employee
{

    private String firstName;
    private String lastName;
    private boolean workStatus;
    private int age;

    public Employee(String firstName, String lastName, boolean workStatus, int age)
    {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
        this.workStatus = workStatus;
        this.age = age;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public boolean isWorkStatus()
    {
        return workStatus;
    }

    public void setWorkStatus(boolean workStatus)
    {
        this.workStatus = workStatus;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    @Override
    public String toString()
    {
        return "Employee [firstName=" + firstName + ", lastName=" + lastName + ", workStatus=" + workStatus + ", age=" + age + "]";
    }

}

The "usual" thing: you don't understand what you are doing. “平常”的事情:您不了解自己在做什么。

Meaning: it is not sufficient to "just create" a mock object. 含义:仅“创建”模拟对象是不够的。 You have to somehow make sure that the corresponding mocked object is used by the code you are testing, for example by using the @InjectMocks annotation. 你必须以某种方式确保相应的嘲笑对象是正在测试的代码中使用,例如通过使用@InjectMocks注解。

In essence, your real problem is that you started using Mockito without understanding it. 本质上,您真正的问题是您在不了解Mockito的情况下开始使用它。 Inefficient strategy. 低效的策略。 Instead, you should start by reading a good Mockito/Junit tutorial (like this one) top to bottom. 相反,您应该从上至下阅读一本不错的Mockito / Junit教程(如教程)。 To understand what mocks are, and how you should be using them. 了解什么是模拟,以及如何使用它们。 And how you make sure that your code under test makes use of mocked objects. 以及如何确保被测代码使用模拟对象。

The problem here is that you created code that is unnecessary hard to test. 这里的问题是您创建了不必要的难以测试的代码。 Given your current design, you would have to use PowerMock(ito) or JMockit - as you would have to "intercept" this call 根据当前的设计,您将不得不使用PowerMock(ito)或JMockit-因为您将不得不“拦截”此调用

public static final EmployeeFactory INSTANCE = new EmployeeFactory();

Your problem is that you have to control that INSTANCE object. 您的问题是您必须控制该INSTANCE对象。 As you don't have access to that object, you would have to intercept the call to new() , and only PowerMock(ito) or JMockit allow you to do that. 由于您无权访问该对象,因此必须拦截对new()的调用,只有PowerMock(ito)或JMockit允许您执行此操作。

So, the real answer is to make change your design like this for example: 因此,真正的答案是像这样改变您的设计:

public class Check { 
   private final EmployeeFactory factory;
   public Check() { this(EmployeeFactory.getInstance()); } 

   Check(EmployeeFactory factory) { this.factory = factory }

  public String myCheck() {
    List<Employee> employee = factory.getEmployee();
    ...

And now you can use that argument-taking constructor to easily injected a mocked factory object that returns what you need to return. 现在你可以使用这个参数,以构造很容易地注入了嘲笑工厂对象,返回你需要返回什么。

Instead of calling a static factory method, inject the factory (maybe in the constructor) and use it in the class. 而不是调用静态工厂方法,而是注入工厂(可能在构造函数中)并在类中使用它。 That way you are decoupling the class and you will be able to inject a mock instead of a real implementation during the testing phase. 这样,您就可以取消类的耦合,并且可以在测试阶段注入模拟而不是实际的实现。 Little example: 小例子:

class EmployeeFactory{
  public Employee getEmployee(){...}
}

class Check{
  private EmployeeFactory factory;
  public Check(EmployeeFactory factory){ this.factory = factory;

  public String myCheck()
  {
    List<Employee> employee = factory.getEmployee();
}

In the mock: 在模拟中:

public class Check_Test extends TestCase
{
    public void testMyCheck()
    {
        EmployeeFactory employeeFactoryMock = Mockito.mock(EmployeeFactory.class);
        Check checkObj = new Check(employeeFactoryMock);
        Mockito.doReturn(Collections.EMPTY_LIST).when(employeeFactoryMock).getEmployee();
        String str = checkObj.myCheck();
        assertEquals("", str);
    }
}

The mock instance isn't being used at all. 完全不使用模拟实例。 Your test is still using the singleton created inside the EmployeeFactory class. 您的测试仍然使用在EmployeeFactory类内部创建的单例。

In order to correct the situation, you would need to permit the singleton instance to be injected so that it can use a mock during testing and an actual instance in the release build. 为了纠正这种情况,您需要允许注入单例实例,以便它可以在测试过程中使用模拟,并在发行版本中使用实际实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM