0

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

}
Manish Kumar
  • 227
  • 4
  • 9
  • Could you try this syntax? `when(employeeFactoryMock.getEmployee()).thenReturn(Collections.emptyList());` – Ron Nabuurs May 16 '18 at 14:29
  • Exactly. Dont use Collections.EMPTY_MAP, but the emptyMap() method. And with newer Javas, you also dont need the `` part. – GhostCat May 16 '18 at 14:29
  • @RonNabuurs : Yes I tried this also, not working yet. – Manish Kumar May 17 '18 at 05:07
  • I updated my answer with more information. But please note that many more things with your code are ... not good. Some of the names you are using are pointless (like class Check , myCheck ... tell you nothing about what is checked) or even misleading (like using `employee` which indicates singular to hold a **list** of employees). It is also very strange to have that static helper class, and actually: the whole factory design there is just "wrong". – GhostCat May 17 '18 at 08:27
  • This is not a original code, I created the scenarios for developer understanding so that I can get the solution ASAP. You could ignore the class and method naming conversion here. – Manish Kumar May 17 '18 at 13:02

3 Answers3

5

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.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
1

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);
    }
}
Edwin Miguel
  • 409
  • 4
  • 11
0

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.

Dave
  • 4,282
  • 2
  • 19
  • 24