Manish Kumar
Manish Kumar

Reputation: 227

Mockito not returning expected value

I am using the JUnit and Mockito library to test my application. 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

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...

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???

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...

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 + "]";
    }

}

Upvotes: 0

Views: 8042

Answers (3)

GhostCat
GhostCat

Reputation: 140427

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.

In essence, your real problem is that you started using Mockito without understanding it. Inefficient strategy. Instead, you should start by reading a good Mockito/Junit tutorial (like this one) top to bottom. 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

public static final EmployeeFactory INSTANCE = new EmployeeFactory();

Your problem is that you have to control that INSTANCE object. 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.

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.

Upvotes: 4

Edwin Miguel
Edwin Miguel

Reputation: 409

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);
    }
}

Upvotes: 1

Dave
Dave

Reputation: 4291

The mock instance isn't being used at all. Your test is still using the singleton created inside the EmployeeFactory class.

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.

Upvotes: 0

Related Questions