Question

Method to be tested:

public boolean isValidStudent(String fName, String lName){
    Student student = new Student(fName, lName);//-----------this creates problem
    return (studentDao.get(student).isEmpty())?false : true;        
}

The below test fails because the method stub always returns an empty list, when I have specifically specified it to return the list I have created. It seems that the student object in the test and the method are different. What can I do to make it work? I fixed this by changing the method signature in my second approach below. But I want to do it without changing my method.

@Mock
Service service;

@Test
public void isValidStudent(){
    studentList = new ArrayList<Student>();
    studentList.add(new Student());
    studentList.add(new Student());

    Student student = new Student("Tom", "Clancy");//---this creates problem. 

    when(studentDao.get(student)).thenReturn(studentList);
    assertTrue(service.isValidStudent("Tom", "Clancy"));
}

Second approach that works:

In this approach, I changed the method signature to accept student object instead and it worked fine. I instantiate the student object only once in my test and use it for method stubbing as well as pass it to the method under test.

public boolean isValidStudent(Student student){
    return (studentDao.get(student).isEmpty())?false : true;        
}

@Mock
Service service;

@Test
public void isValidStudent(){
    studentList = new ArrayList<Student>();
    studentList.add(new Student());
    studentList.add(new Student());

    Student student = new Student("Tom", "Clancy");

    when(studentDao.get(student)).thenReturn(studentList);
    assertTrue(service.isValidStudent(student));
}
Was it helpful?

Solution

Hypothesis: your Student class does not implement .equals()/.hashCode().

By default, when() you mock a method call, mockito will check whether its argument(s) .equals() the one(s) you have passed it as (an) argument(s) to the mocked method.

However, if you don't implement .equals(), then you will have the case that:

final Student s1 = new Student("foo", "bar");
final Student s2 = new Student("foo", "bar");
s1.equals(s2); // <--- FALSE!

And this is what happens here. In your first scenario, you create a Student which appears, to you, logically equal but that is not what Mockito wants. Therefore, in your first scenario, .get() will return null.

In your second however, you pass the same reference; since you don't implement .equals(), Object's .equals() takes place, and for this .equals() implementation, obj1.equals(obj2) if and only if obj1 == obj2 -- which is the case. Continuing the code above, in your case:

s1 == s2; // FALSE! (as in first test)
s1 == s1; // true   (as in second test)

If you wanted to be more "loose" to arguments, you'd have to write custom argument matchers; Mockito can also do that (with the help of its hamcrest dependency).

All this banter to say that you should solve your problem by making your Student class implement .equals()/.hashCode().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top