Search code examples
javaspring-bootmockitospring-boot-test

How can I set field that is not a bean for a mockbean


I'm developing a MessageHandler class which contains a Cache field which is also I developed, MessageHandler is annotated as a @Component and Cache is not bean.

When using Spring-boot-test to test the MessageHandler class, I use @Mockbean to mock a MessageHandler and try to use setter to set a Cache object for the mock bean. But when I run test to see if MessageHandler has a cache, I got null.

My code is as follows:


@MockBean(value = HiMessageHandler.class)
MessageHandler messageHandler;

public void setUp(){
       Cache cache=new Cache();
       cache.offer(new HiMessage("1","1","1"));
       messageHandler.setCache(cache);
  }


@Test
public void testConsume() throws Exception {
    setUp();
    System.out.println(messageHandler.getCache());
}

I want to know how to set a field that is not a bean for a mock bean.


Solution

  • I think the main issue here is that you try to mock the class that you test.

    You test MessageHandler class in an integration test (otherwise, if its a unit test - then spring boot test is not required)

    So the goal is to check that the code that you wrote in MessageHandler really works, and since its an integration test, probable with an emphasis on interaction with other real/semi-real components.

    Side note, if you're not sure about the difference between unit and integration tests feel free to read my answer on this question or just google, it will provide more valuable resources for sure, the point is you should clearly understand the difference between the two and pick the right tool for the job.

    On the other hand, when you use @MockBean annotation, Spring creates a Mock for your bean, and puts this mock instead of the real bean into application context, so that other beans, if dependent on this message handler, could get the reference on this mock instead of the reference on the real bean.

    Then you call some method on a mock (setCache) and indeed it doesn't work, because mock is not a real thing, its a mock, the correct way to interact with mock is to specify interaction rules (style when(...).thenReturn(...) in mockito syntax). Yes, it doesn't work, so this is a direct answer on your question, but as I've explained above the issue is deeper here IMHO.