Suche…


Einfaches Mock

Mockito bietet eine einheitliche Größe, um (nicht endgültige) Klassen und Schnittstellen zu erstellen.

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

Dadurch wird eine Scheininstanz der Dependency unabhängig davon, ob die Dependency eine Schnittstelle oder Klasse ist.

Es ist dann möglich, Methodenaufrufe für diesen Mock mit der Mockito.when (x) .thenReturn (y) -Notation zu unterdrücken.

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

Das heißt, Aufrufe von Dependency.possiblyBuggyMethod() einfach "someString" .

In den meisten Anwendungsfällen wird von einer anderen Notation abgeraten, da sie nicht typensicher ist.

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

Spott mit Standardwerten

Während ein einfacher Mock für jeden Aufruf Null (oder Standardwerte für Grundelemente) zurückgibt, ist es möglich, dieses Verhalten zu ändern.

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

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

oder mit Lambdas:

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

Diese Beispiele geben bei jedem Aufruf "someString" zurück, es ist jedoch möglich, eine beliebige Logik in der Antwortmethode zu definieren.

Eine Klasse mit Anmerkungen verspotten

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

Das Verhalten dieser Schnittstelle wird verspottet:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Nehmen Sie die tatsächliche Implementierung des 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;
    }
}

Junitest mit 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" für partiellen Spott

@Spy-Annotation (oder -Methode ) kann verwendet werden, um ein Objekt teilweise zu verspotten. Dies ist nützlich, wenn Sie das Verhalten einer Klasse teilweise simulieren möchten. Angenommen, Sie verfügen über eine Klasse, die zwei verschiedene Dienste verwendet, und Sie möchten nur einen von ihnen verspotten und die tatsächliche Implementierung des anderen Dienstes verwenden.

Randbemerkung: Obwohl dies philosophisch gesehen, würde ich dies nicht als einen "reinen Komponententest" bezeichnen, da Sie eine echte Klasse integrieren und Ihre getestete Klasse nicht isoliert testen. Nichtsdestotrotz könnte dies in der realen Welt tatsächlich nützlich sein und ich verwende es oft, wenn ich die Datenbank mit einigen in der Datenbankspeicherimplementierung verspotteten, damit ich echte DAOs verwenden kann.

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

Das Verhalten dieser Schnittstelle wird verspottet:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Nehmen Sie die tatsächliche Implementierung des 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;
    }
}

Das Verhalten dieser Schnittstelle wird nicht verspottet:

public interface AppService {
    String getAppName();
}

Nehmen Sie die tatsächliche Implementierung von 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;
    }
}

Junitest mit 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);
    }
}

Festlegen von privaten Feldern in abgespeicherten Objekten

In Ihrer Klasse, die gerade getestet wird, verfügen Sie möglicherweise über private Felder, auf die nicht einmal über den Konstruktor zugegriffen werden kann. In solchen Fällen können Sie mit Reflection solche Eigenschaften festlegen. Dies ist ein Ausschnitt aus einem solchen 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
}

Ich verwende Sptring des ReflectionTestUtils.setField(Object targetObject, String name, Object value) Methode hier zu vereinfachen, aber man kann die gleiche einfache alte Java - Reflexion zu tun verwenden.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow