Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to Mock and ignore properties

I'm changing our identity strategy and we're using an ID that is generated before the Entity is written to the database. This change is causing some of our tests to fail due to the way we're mocking some service calls.

TimeLog timeLog = buildTimeLog('123456', mockEmployeeId);
TimeLog mockTimeLog = buildTimeLog('123456', mockEmployeeId);
when(this.timeLogService.save(mockTimeLog)).thenReturn(timeLog);

When the test makes the call to the Controller, the bound entity in the Controller gets a different ID than the mock that is expected because the Entity generates the ID. Whereas before, the database generated the ID so the mocks worked.

If there is a way to tell Mockito to ignore a property in the expectation? That would solve the problem and the test would still be valid. Otherwise, other approaches are welcome.

like image 584
Gregg Avatar asked Nov 18 '25 10:11

Gregg


1 Answers

You can't tell mockito to ignore a property in an expectation because it's using the java "equals" method... You can define an equals method in TimeLog that igonres ID but I suspect that won't give you what you want. The other approach is, instead of trying to tell mockito what not to verify, define explicitly what it is to verify using a hamcrest matcher. Define a hamcrest matcher which just matches the fields you want to verify i.e. all fields other than ID. So something like:

private class TimeLogMatcher extends TypeSafeMatcher<TimeLog> {
    private final EmployeeId employeeId;

    public TimeLogMatcher(EmployeeId employeeId) {
        this.employeeId = employeeId;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("TimeLog with employeeId=" + employeeId);
    }

    @Override
    public boolean matchesSafely(TimeLog item) {
        return employeeId.equals(item.getEmployeeId());
    }
}

And then instead of calling whatever your "buildTimeLog" method is doing call into the mockito Matchers class like:

TimeLog timeLog = Matchers.argThat(new TimeLogMatcher(mockEmployeeId));

Or alternatively you could always use an Answer object:

when(this.timeLogService.save(any(TimeLog.class)).thenAnswer(new Answer<TimeLog> {
    public TimeLog answer(InvocationOnMock invocation) throws Throwable {
        TimeLog receivedTimeLog = invocation.getArgumentAt(0, TimeLog.class);
        assertThat(receivedTimeLog.getEmployeeId(), equalTo(mockEmployeeId));
        return timeLog;
    }
});

Does that all make sense?

like image 133
John Stringer Avatar answered Nov 20 '25 22:11

John Stringer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!