Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@MockBean and @Autowired of the same service in one test class

Is it possible to somehow have in the same test class @MockBean and @Autowired of the same service?

In other words, I would like to have @MockBean service only for one test, while for others tests of the same class I need it as @Autowired.

like image 397
Mikhail Geyer Avatar asked Apr 21 '20 07:04

Mikhail Geyer


People also ask

Can you Autowire by type when more than one being with the same type exist?

Autowiring using property type. Allows a property to be autowired if exactly one bean of property type exists in the container. If more than one exists, it's a fatal exception is thrown, which indicates that you may not used byType autowiring for that bean.

Can we use @autowired in a class?

A class that uses the repository class: public class MyClass extends AbstractClass { @Autowired private MyRepository myRepository; //... } I know that if I annotate my MyClass with @Component and use it with an @Autowired , then the @Autowired MyRepository is resolved just fine.

What is difference between @mock and @MockBean?

We can use the @MockBean to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context. If no bean of the same type is defined, a new one will be added.

What is the difference between @bean and @autowired?

@Bean is just for the metadata definition to create the bean(equivalent to tag). @Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).


2 Answers

This relies on the difference between @MockBean and @Autowired.

@Autowired

only does a lookup in the SpringContext for a bean of that type. This means that you will need to create that bean if you need to 'autowire' it

@MockBean

does exactly what you expect from the name, it creates a 'mock' of the service, and injects it as a bean.

so this

class MyTest {
   @MockBean
   MyService myService;
}

is equivalent to this

@Import(MyTest.Config.class)
class MyTest {

   @Autowired
   MyService myService;

   @TestConfiguration
   static class Config {

      @Bean
      MyService myService() {
         return Mockito.mock(MyService.class);
      }
   }
}

So, if you need to have a different bean of the MyService type in other tests, you need to create the bean in a @TestConfiguration annotated class

@Import(MyTest.Config.class)
class MyTest {

   @Autowired
   MyService myService;

   @TestConfiguration
   static class Config {

      @Bean
      MyService myService() {
         return new MyServiceImpl();
      }
   }
}

Or, in a class annotated with @Configuration

@Import(MyConfig.class)
class MyTest {
   @Autowired
   MyService myService;
}

@Configuration
public class MyConfig {
   @Bean
   MyService myService() {
      return new MyServiceImpl();
   }
}
like image 149
Ahmed Sayed Avatar answered Sep 28 '22 06:09

Ahmed Sayed


The best solution is to change @MockBean to @SpyBean. And in the method you will be able to do like this:

kotlin

    @SpyBean
    lateinit var serviceMock: Service

    @Test
    fun smallTest()
        `when`(serviceMock.doSomething())
            .thenReturn(false)

        // your test logic
    }

like image 44
Dmitry Kaltovich Avatar answered Sep 28 '22 05:09

Dmitry Kaltovich