Mocking and Stubbing in Unit Tests

Introduction to Testing in Java

Maria Milusheva

Senior Software Engineer

Motivation: Dependencies

Recall the dependency flow in the previous lesson: The currency exchange app depends on the bank server: A Mermaid graph of the dependency flow in the banking demo

Impossible to verify calculations because currency exchange rates are inherently unpredictable.

Introduction to Testing in Java

Dependency management in testing

Mocking - creating simulated objects or behaviors for real objects that are difficult to use in tests, allowing us to test without relying on external dependencies.

Mockito - powerful Java library for creating mocks.

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Mocking example

Introduction to Testing in Java

Mocking

  • Mock = like a stand-in actor in a play, pretending to be the real object only as far as the test is concerned

Consider the previous lesson:

public double convertEuroTo(String currency, double amount) {
    double rate = this.bank.getRateEuroTo(currency);
    return amount * rate;
}

➡ Make predicable object for EuropeanCentralBankServer for testing

Introduction to Testing in Java

Mocking: Currency exchange

This is how we test with mocks:

@Test
void convert_returnsExpectedValue() {
    EuropeanCentralBankServer bank = mock(EuropeanCentralBankServer.class);
    ExchangeApp exchangeApp = new ExchangeApp(bank);

// Need to program the mock so it works when(bank.getRateEuroTo("USD")).thenReturn(1.1);
// Calls getRateEuroTo from the mock object, obtaining our pre-programmed values double result = exchangeApp.convertEuroTo("USD", 1000); assertEquals(1100, result); // We can now assert on exact return values }
Introduction to Testing in Java

Common mistake

We should never forget to program our mocks:

@Test
void convert_returnsExpectedValue() {
    EuropeanCentralBankServer bank = mock(EuropeanCentralBankServer.class);
    ExchangeApp exchangeApp = new ExchangeApp(bank);

    // No mock programming - mock bank object doesn't know how to respond to getRateEuroTo
    double result = exchangeApp.convertEuroTo("USD", 1000);

    assertEquals(1100, result); // Will fail due to lack of mock setup
}
Introduction to Testing in Java

Stubbing

The test fails with:

org.opentest4j.AssertionFailedError: 
Expected :1100.0
Actual   :0.0

Programming a mock is referred to as stubbing.

Stubbing - providing minimal, pre-defined answers to calls made during the test, usually not responding at all to anything outside what’s programmed for the test.

Introduction to Testing in Java

Exceptions with Mockito

Mockito can also simulate error scenarios:

EuropeanCentralBankServer bank = mock(EuropeanCentralBankServer.class);
ExchangeApp exchangeApp = new ExchangeApp(bank);
// Instead of thenReturn() use thenThrow()
when(bank.getRateEuroTo("USD"))
        .thenThrow(new RuntimeException("Bank server unavailable."));

exchangeApp.convertEuroTo("USD", 1000); // getRateEuroTo will throw exception
Introduction to Testing in Java

Let's practice!

Introduction to Testing in Java

Preparing Video For Download...