Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring - replace @Service bean in test

In my spring boot application I have a service bean (with @Service annotation) and I want to mock this service in particular JUnit test (not in all tests). How can I replace this service bean for just one particular test?

Service declared as:

@Service
public class LocalizationServiceImpl implements LocalizationService {
   ...
}

App configuration class:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages="my.package")
@EntityScan

public class Application {
...
}

Test class:

@Transactional
@SpringApplicationConfiguration(classes = LocalizationServiceTest.LocalizationServiceTestConfig.class)
public class LocalizationServiceTest extends ESContextTest {

    @Autowired
    private LocalizationService locService;

    @Configuration  
    public static class LocalizationServiceTestConfig {

        @Bean
        public LocalizationService localizationServiceImpl() {
            return mock(LocalizationService.class);
        }

    }
}

And test class parent:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public abstract class ESContextTest {
...
}

But this does not work. When I run the test then original LocalizationServiceImpl is used for autowired locService property. This appeared in log file: Skipping bean definition for [BeanMethod:name=localizationService,declaringClass=...LocalizationServiceTest$LocalizationServiceTestConfig]: a definition for bean 'localizationService' already exists. This top-level bean definition is considered as an override.

When I use different name for @Bean method in LocalizationServiceTestConfig e.g. localizationServiceMock() (to be different from original implementation classname) then spring throws

'No qualifying bean of type is defined: expected single matching bean but found 2: localizationServiceImpl,localizationServiceMock'

So I thought it is correct to use the same name.

Only working solution is to remove @Service annotation from LocalizationServiceImpl class and create configuration for normal (not test) app run like

@Configuration 
public class BeansConfig {
    @Bean
    public LocalizationService localizationServiceImpl() {
        return new LocalizationServiceImpl();
    }
}

Then in test run the correct mock implementation is autowired.

But it should be possible to do the same via @Service annotation, shouldn't?

Thanks for advice.

like image 492
komo Avatar asked Aug 05 '15 15:08

komo


People also ask

How to initialize beans for testing class only in Spring Boot?

In Spring Boot, we can create a @TestConfigurationclass to initialize some beans for testing class only. P.S Tested with Spring Boot 2 1. @TestConfiguration + @Import This @TestConfigurationclass will not pick up by the component scanning, we need to import it manually.

What is @testconfiguration annotation in Spring Boot?

In Spring Boot, @TestConfiguration annotation can be used to define/override beans for unit tests. @TestConfiguration classes (in test folder) can only be used by selective test classes which explicitly want to import them via @import annotation. @Configuration classes (in test folder), are available for all tests without explicitly importing them.

Is it possible to test service in spring?

The given answer seems useful but just in case it can help someone, testing service is not so obvious in Spring (IMHO). The SpyBean annotation turns out to be really handy:

What is @service in Spring Boot?

@Service on Concrete Classes Contrary to what we've seen above, it's quite a common practice to annotate the implementation classes instead of abstract classes or interfaces. In this way, our goal is mostly to tell Spring this class is going to be a @Component and mark it with a special stereotype, which is @Service in our case.


1 Answers

Found a solution by myself: rename localizationServiceImpl() e.g. to localizationServiceMock() in class LocalizationServiceTestConfig and annotate the method with @Primary.

But why simply redefining bean with the same 'id' doesn't work like via xml-config?

like image 154
komo Avatar answered Sep 21 '22 03:09

komo