Sök…


Enkel håna

Mockito erbjuder en one-size-fit-all mehtod för att skapa håravfall till (icke-slutgiltiga) klasser och gränssnitt.

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

Detta skapar en hålig förekomst av Dependency oavsett om Dependency är ett gränssnitt eller klass.

Det är då möjligt att stoppa metodsamtal till det håna med hjälp av Mockito.when (x) .thenReturn (y) notation.

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

Så att samtal till Dependency.possiblyBuggyMethod() helt enkelt returnerar "someString" .

Det finns en annan notation som är avskräckt i de flesta användningsfall eftersom den inte är typisk.

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

Hån med standardvärden

Medan en enkel håna returnerar noll (eller standardinställningar för primitiv) till varje samtal, är det möjligt att ändra det beteendet.

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

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

eller med lambdas:

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

Dessa exempel returnerar "someString" till varje åkallelse men det är möjligt att definiera någon logik i svarsmetoden.

Hånar en klass med anteckningar

Klass under test:

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;
    }
}

Det här gränssnittets beteende kommer att hånas:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Anta faktiskt implementering av 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 med 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);
    }
}

"Spy" för delvis hån

@Spy-kommentar (eller metod ) kan användas för att delvis håna ett objekt. Detta är användbart när du delvis vill håna beteende hos en klass. Antag t.ex. att du har en klass som använder två olika tjänster och att du bara vill håna en av dem och använda själva implementeringen av den andra tjänsten.

Sidanmärkning: Även om filosofiskt skulle jag inte betrakta detta som ett "rent enhetstest" i verklig mening, eftersom du integrerar en riktig klass och inte testar din klass under test i fullständig isolering. Ändå kan detta vara faktiskt användbart i den verkliga världen och jag använder den ofta när jag hånar databasen med hjälp av vissa i minnesdatabasimplementering så att jag kan använda riktiga DAO: er.

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;
    }
}

Det här gränssnittets beteende kommer att hånas:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Anta faktiskt implementering av 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;
    }
}

Det här gränssnittets beteende kommer inte att hånas:

public interface AppService {
    String getAppName();
}

Anta faktiskt implementering av 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 med 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);
    }
}

Ställ in privata fält i förlöjliga objekt

I din klass som testas kan du ha några privata fält som inte är tillgängliga ens genom konstruktör. I sådana fall kan du använda reflektion för att ställa in sådana egenskaper. Detta är ett utdrag från ett sådant 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
}

Jag använder Sptring s ReflectionTestUtils.setField(Object targetObject, String name, Object value) metod för att förenkla, men du kan använda vanliga gamla Java Reflection att göra detsamma.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow