Home > OS >  Dependency injection with mockito example
Dependency injection with mockito example

Time:05-23

I am very new with Mockito and I don't get the following example (classes were provided, only test to write) and how to solve it. What I try to do is use a test double for the supplier so that we can control the returned greeting in the test and assert that the GreetingService does not modify the greeting message in any way. Then assert that the returned greeting string is equal to "Hello Andy.".

public class Greeting {
    private final String template;

    public Greeting(String template) {
        this.template = template;
    }

    public String forName(String world) {
        return String.format(template, world);
    }
}
@Component
public class GreetingService {

    private final Supplier<Greeting> greetingSupplier;

    public GreetingService(Supplier<Greeting> greetingSupplier) {
        this.greetingSupplier = greetingSupplier;
    }

    public String greet(String name) {
        return greetingSupplier.get().forName(name);
    }
}
@Component
public class RandomGreetingSupplier implements Supplier<Greeting> {

    private final List<Greeting> greetings = Arrays.asList(
            new Greeting("Hello %s."),
            new Greeting("Hi %s!"),
    );
    private final Random random = new Random();

    @Override
    public Greeting get() {
        return greetings.get(random.nextInt(greetings.size()));
    }
}
@SpringBootTest
public class GreetingServiceTest {

    @Autowired
    GreetingService greetingService;

    @MockBean
    Supplier<Greeting> greetingSupplier;

    @Test
    void getGreetingForPerson() {
        String name = "Andy";
        // that test cannot know which greeting will be returned by the supplier
        // WHY IS IT NULLPOINTEREXCEPTION AFTER INITIALIZING @MockBean
        //String greeting = greetingService.greet(name); 
        //assertThat(greeting).contains(name);
        
        // WROTE SUCH TEST HERE -> NullPointerException WHY?
        Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");
        assertThat(greetingSupplier.equals("Hello Andy."));
  
        // THIS IS WORKING & TEST PASSED BUT I GUESS ITS WRONG?
        Mockito.when(greetingSupplier.get()).thenReturn(new Greeting("Hello %s."));
        assertThat(greetingSupplier.equals("Hello Andy."));
   
    }
}

CodePudding user response:

Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");

You can't chain calls like that, you need to produce intermediate results, like

Supplier<Greeting> supplier = mock(Supplier.class);
Mockito.when(supplier).forName().thenReturn("Hello %s.");
Mockito.when(greetingSupplier.get()).thenReturn(supplier);

For dependency injection, you need to create the subject under test with the mocked Supplier. You can do that in a @Before method for example.

CodePudding user response:

Your mocking is wrong.

Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");

You mocked Supplier<Greeting> and the default behavior is to return null. So when you call greetingSupplier.get() in your first line it returns null. You directly chain forName which nou basicall is null.forName which leads to an error.

Your second part is actually (kind of) correct.

Mockito.when(greetingSupplier.get()).thenReturn(new Greeting("Hello %s."));

You now properly return a response from greetingSupplier.get(). Instead of chaining the call.

However I would argue that your excercise is wrong. Why? When using a Supplier<?> in Spring it actually is a lazy beanFactory.getBean call. You can lazily inject dependencies this way. You should have a mock for Greeting which returns a hardcoded String which you can check.

  • Related