komo
komo

Reputation: 279

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.

Upvotes: 9

Views: 3836

Answers (1)

komo
komo

Reputation: 279

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?

Upvotes: 12

Related Questions