简体   繁体   中英

How to mock a spring bean?

I'm trying to mock an class that uses JAXRS and this class are a spring component.

@Component
public class PostmanClient {

  private WebTarget target;

  public PostmanClient() {
    Client client = ClientBuilder.newClient();
    target = client.target(...);
  }

  public String send(String xml) {
    Builder requestBuilder = target.request(MediaType.APPLICATION_XML_TYPE);
    Response response = requestBuilder.post(Entity.entity(xml, MediaType.APPLICATION_XML_TYPE));
    return response.readEntity(String.class);
  }
}

This is my test method:

@Test
public void processPendingRegistersWithAutomaticSyncJob() throws Exception {
  PostmanClient postmanClient = mock(PostmanClient.class);
  String response = "OK";
  whenNew(PostmanClient.class).withNoArguments().thenReturn(postmanClient);
  when(postmanClient.send("blablabla")).thenReturn(response);

  loadApplicationContext(); // applicationContext = new ClassPathXmlApplicationContext("/test-context.xml");
}

When i debug the postmanClient instance, its a instance created by Spring and not a mock. How can i avoid this behavior and get a mock instance ?

If you are using PowerMock with Spring, you should consider following tips:
1. Use @RunWith(SpringJunit4Runner.class)
2. Use @ContextConfiguration("/test-context.xml") // load spring context before test
3. Use @PrepareForTest(....class) // to mock static method
4. Use PowerMockRule
5. The simplest way to mock a spring bean is to use springockito

Back To You Question :
If I don't understand you wrong, you have PostmanClient defined in spring context, which means, you only need use springockito to achieve your goal, just follow the tutorial on springockito page.

You can use BDD framework Spock to write UT for your Spring Framework. With Spock Spring extension (Maven: groupId:org.spockframework, artifactId:spock-spring), you can load Spring context in your unit test.

@WebAppConfiguration
@ContextConfiguration(classes = Application.class)
class MyServiceSpec extends Specification {
    @Autowired
    UserRepository userRepository
}

If you have some beans you want to mock them instead of loading from Spring context, you can add following annotation on the bean you want to mock.

@ReplaceWithMock

This article has the detailed intro about how to write UT for your Spring app with Spock.

Im not sure what is wrong with your implementation. Maybe PostmanClient should be an interface instead of class?

However I've implemented a similar unit test in my practice/test project. Maybe it will help:

https://github.com/oipat/poht/blob/683b401145d4a4c2bace49f356a5aa401fe81eb1/backend/src/test/java/org/tapiok/blogi/service/impl/PostServiceImplTest.java

Register your mock with Spring-ReInject before the application context starts in your test's constructor. The original bean will be replaced with a mock, and the mock will be used by Spring everywhere, including injected fields. The original bean will be never created.

There is an option to fake Spring bean with just plain Spring features. You need to use @Primary , @Profile and @ActiveProfiles annotations for it.

I wrote a blog post on the topic.

I've created the example to answer another question, but also cover your case. Simple replace MockitoJUnitRunner via SpringJUnit4ClassRunner .

In nutshell, I create Java Spring Configuration which includes only classes which should be tested/mocked and returns mocked object instead really object, and then give Spring does it work. Very simple and flexible solution.

It also works fine with MvcMock

从Spring Boot 1.4.x开始,您可以使用名为@MockBean的新注释。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM