Zoeken…


Simple Mock

Mockito biedt een one-size-fits-all mehtod om mocks van (niet-definitieve) klassen en interfaces te maken.

Dependency mock = Mockito.mock(Dependency.class);

Dit creëert een schijnexemplaar van Dependency ongeacht of Dependency een interface of klasse is.

Het is dan mogelijk om methodeaanroepen naar die mock te sturen met behulp van de Mockito.when (x) .thenReturn (y) notatie.

Mockito.when(mock.possiblyBuggyMethod()).thenReturn("someString");

Dus dat roept Dependency.possiblyBuggyMethod() eenvoudigweg "someString" .

Er is nog een notatie die in de meeste gevallen wordt afgeraden omdat deze niet typeveilig is.

Mockito.doReturn("someString").when(mock).possiblyBuggyMethod()

Mock met standaardwaarden

Hoewel een eenvoudige mock null (of standaardwaarden voor primitieven) retourneert voor elke aanroep, is het mogelijk dat gedrag te wijzigen.

Dependency mock = Mockito.mock(Dependency.class, new Answer() {

        @Override
        public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
            return "someString";
        }
    });

of met behulp van lambdas:

Dependency mock = Mockito.mock(Dependency.class, (Answer) invocationOnMock -> "someString");

Dit voorbeeld retourneert "someString" naar elke aanroep, maar het is mogelijk om elke logica in de antwoordmethode te definiëren.

Een klas bespotten met annotaties

Klasse die wordt getest:

public class GreetingsService { // class to be tested in isolation
    private UserService userService;

    public GreetingsService(UserService userService) {
        this.userService = userService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

Het gedrag van deze interface wordt bespot:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Ga uit van daadwerkelijke implementatie van de UserService :

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

Junit-test met Mockito:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe!", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe!", greetings);
    }
}

"Spion" voor gedeeltelijke bespotting

@Spy annotatie (of methode ) kan worden gebruikt om een object gedeeltelijk te bespotten. Dit is handig als u het gedrag van een klas gedeeltelijk wilt bespotten. Stel dat u een klasse hebt die twee verschillende services gebruikt en dat u slechts één daarvan wilt bespotten en de daadwerkelijke implementatie van de andere service wilt gebruiken.

Kanttekening: hoewel ik filosofisch gezien dit niet als een "pure eenheidstest" zou beschouwen, omdat je een echte klasse integreert en je geteste klasse niet volledig geïsoleerd test. Desalniettemin kan dit in de echte wereld nuttig zijn en ik gebruik het vaak wanneer ik de database bespot met behulp van een aantal in de geheugendatabase-implementatie, zodat ik echte DAO's kan gebruiken.

Class under test:
public class GreetingsService { // class to be tested in isolation
    private UserService userService;
    private AppService appService;

    public GreetingsService(UserService userService, AppService appService) {
        this.userService = userService;
        this.appService = appService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        greetings.append(" Welcome to ")
                .append(appService.getAppName()) // actual method call will be made
                .append(".");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

Het gedrag van deze interface wordt bespot:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Ga uit van daadwerkelijke implementatie van de UserService :

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

Het gedrag van deze interface wordt niet bespot:

public interface AppService {
    String getAppName();
}

Ga uit van de daadwerkelijke implementatie van AppService :

public class AppServiceImpl implements AppService {
    @Override
    public String getAppName() {
        // assume you are reading this from properties file
        String appName = "The Amazing Application";
        return appName;
    }
}

Junit-test met Mockito:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @Spy
    private AppServiceImpl appService; // this class WON'T be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService, appService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe! Welcome to The Amazing Application.", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe! Welcome to The Amazing Application.", greetings);
    }
}

Stel privévelden in bespotte objecten in

In je klasse die wordt getest, heb je mogelijk enkele privévelden die zelfs niet via constructor toegankelijk zijn. In dergelijke gevallen kunt u reflectie gebruiken om dergelijke eigenschappen in te stellen. Dit is een fragment van een dergelijke JUnit-test.

@InjectMocks
private GreetingsService greetingsService = new GreetingsService(); // mocking this class

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    String someName = "Some Name";
    ReflectionTestUtils.setField(greetingsService, // inject into this object
        "name", // assign to this field
        someName); // object to be injected
}

Ik gebruik Sptring's ReflectionTestUtils.setField(Object targetObject, String name, Object value) methode hier te vereenvoudigen, maar je kunt gewoon oude Java Reflectie gebruiken om hetzelfde te doen.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow