14

Consider the scenario where I am mocking certain service and its method.

Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");

//assert
assertEquals("Jim", emp.getName(1));
assertEquals("Mark", emp.getName(2));

In the above code when emp.getName(1) is called then mock will return Jim and when emp.getName(2) is called mock will return Mark. My Question is I am declaring the behavior of Mock and checking it assertEquals what is the point in having above(or same kind of) assert statements? These are obviously going to pass. it is simply like checking 3==(1+2) what is the point? When will these tests fail (apart from changing the return type and param type)?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • I'm not sure that it's an exact duplicate, but I answered a similar question in 2016 with ["Why are mocking test frameworks helpful?"](https://stackoverflow.com/q/40593477/1426891). – Jeff Bowman Feb 09 '18 at 19:21
  • +1 for the question. If anyone got here, [this Answer here](https://stackoverflow.com/a/3623574/3590235) has the best answer IMO. Please take a look. – user3590235 Jul 10 '20 at 19:53

5 Answers5

7

As you noted, these kind of tests are pointless (unless you're writing a unit test for Mockito itself, of course :-)).

The point of mocking is to eliminate external dependencies so you can unit-test your code without depending on other classes' code. For example, let's assume you have a class that uses the Employee class you described:

public class EmployeeExaminer {
    public boolean isJim(Employee e, int i) {
        return "Jim".equals(e.getName(i));
    }
}

And you'd like to write a unit test for it. Of course, you could use the actual Employee class, but then your test won't be a unit-test any more - it would depend on Employee's implementation. Here's where mocking comes in handy - it allows you to replace Employee with a predictable behavior so you could write a stable unit test:

// The object under test
EmployeeExaminer ee = new EmployeeExaminer();

// A mock Employee used for tests:
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");

// Assert EmployeeExaminer's behavior:
assertTrue(ee.isJim(emp, 1));
assertFalse(ee.isJim(emp, 2));
Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

In your case you are testing a getter, I don't know why you are testing it and no clue why would you need to mock it. From the code you are providing this is useless.

There is many scenarios where mocking make sense when you write unit-test you have to be pragmatic, you should test behaviors and mock dependencies.

Here you aren't testing behavior and you are mocking the class under test.

rad
  • 1,857
  • 1
  • 20
  • 30
1

There is no point in that test.

Mocks are only useful for injecting dependencies into classes and testing that a particular behaviour interacts with that dependency correctly, or for allowing you to test some behaviour that requires an interface you don't care about in the test you are writing.

Mocking the class under test means you aren't even really testing that class.

If the emp variable was being injected into another class and then that class was being tested, then I could see some kind of point to it.

gmn
  • 4,199
  • 4
  • 24
  • 46
1

Above testcase is trying to test a POJO.

Actually, You can ignore to test POJO's, or in other words, they are automatically tested when testing other basic functionalities. (there are also utilities as mean-beans to test POJO's)

Goal of unit-testing is to test the functionality without connecting to any external systems. If you are connecting to any external system, that is considered integration testing.

Mocking an object helps in creating mock objects that cannot be created during unit-testing, and testing behavior/logic based on what the mocked object (or real object when connecting to external system) data is returned.

Amit Kaneria
  • 5,466
  • 2
  • 35
  • 38
1

Mocks are structures that simulate behaviour of external dependencies that you don't/can't have or which can't operate properly in the context of your test, because they depend on other external systems themselves (e.g. a connection to a server). Therefore a test like you've described is indeed not very helpful, because you basically try to verify the simulated behaviour of your mocks and nothing else.

A better example would be a class EmployeeValidator that depends on another system EmployeeService, which sends a request to an external server. The server might not be available in the current context of your test, so you need to mock the service that makes the request and simulate the behaviour of that.

class EmployeeValidator {
    private final EmployeeService service;
    public EmployeeValidator(EmployeeService service) {
        this.service = service;
    }
    public List<Employee> employeesWithMaxSalary(int maxSalary) {
        List<Employee> allEmployees = service.getAll(); // Possible call to external system via HTTP or so.
        List<Employee> filtered = new LinkedList<>();
        for(Employee e : allEmployees) {
            if(e.getSalary() <= maxSalary) {
                filtered.add(e);
            }
        }
        return filtered;
    }
}

Then you can write a test which mocks the EmployeeService and simulates the call to the external system. Afterwards, you can verify that everything went as planned.

@Test
public void shouldContainAllEmployeesWithSalaryFiveThousand() {
    // Given - Define behaviour
    EmployeeService mockService = mock(EmployeeService.class);
    when(mockService.getAll()).thenReturn(createEmployeeList());

    // When - Operate the system under test
    // Inject the mock
    EmployeeValidator ev = new EmployeeValidator(mockService);
    // System calls EmployeeService#getAll() internally but this is mocked away here
    List<Employee> filtered = ev.employeesWithMaxSalary(5000); 

    // Then - Check correct results
    assertThat(filtered.size(), is(3)); // There are only 3 employees with Salary <= 5000
    verify(mockService, times(1)).getAll(); // The service method was called exactly one time.
}

private List<Employee> createEmployeeList() {
    // Create some dummy Employees
}
QBrute
  • 4,405
  • 6
  • 34
  • 40