I'm trying to junit test a spring boot application. For this question, I have created a simple example that serves to illustrate my issue.
A service bean:
@Service
public class DummyService {
public String dummyMethod(String str) {
return "Dummy(" + str + ")";
}
}
an entity class:
@Entity
public class KeyValue {
@Id
@GeneratedValue
Long id;
@Column(nullable = false)
String key;
@Column(nullable = false)
String value;
}
and a repository:
public interface KeyValueRepository extends CrudRepository<KeyValue, Long>
{
}
All of these are @Autowired into a controller.
For Unit testing, I have created a Configuration class:
@Configuration
public class MyTestConfig {
@Bean
public DummyService dummyService() {
return new DummyService();
}
@Bean
public KeyValueRepository keyValueRepository() {
return Mockito.mock(KeyValueRepository.class);
}
}
If I test it now, it works just perfect:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyTestConfig.class)
public class UsingMockTest {
@Autowired
KeyValueRepository keyValueRepository;
@Test
public void respositoryIsMock()
{
MockUtil mo = new MockUtil();
assertTrue(mo.isMock(keyValueRepository));
}
}
This gives me a mocked version of the repository, as expected.
However, it turns out that this approach is not suitable for a larger application. Our real application contains 50+ beans which are all autowired. So what I would like to do is to @ComponentScan the application and then, in my configuration only override the beans I'd actually want to mock.
However, if I set up the test configuration like this:
@Configuration
@ComponentScan(
basePackages = {"com.example"}
)
public class MyTestConfig {
@Bean
public DummyService thisForThatService() {
return new DummyService();
}
@Bean
public KeyValueRepository sayingRepository() {
return Mockito.mock(KeyValueRepository.class);
}
}
I will get a failed test because the repository is no longer a mock object. When I look at the spring boot log, I see the following:
2016-05-30 15:36:50.539 INFO 5908 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'dummyService' with a different definition: replacing [Generic bean: class [com.example.DummyService]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\work\dev\testDemo\build\classes\main\com\example\DummyService.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=myTestConfig; factoryMethodName=dummyService; initMethodName=null; destroyMethodName=(inferred); defined in com.example.MyTestConfig]
2016-05-30 15:36:50.658 INFO 5908 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'keyValueRepository' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=myTestConfig; factoryMethodName=keyValueRepository; initMethodName=null; destroyMethodName=(inferred); defined in com.example.MyTestConfig] with [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
So, for the simple "DummyBean", the scanned configuration is overridden by my explicit configuration in the MyTestConfig class (which is exactly what I want), but for the CRUD Repository, the mock bean from the MyTestConfig class is overridden by the component-scanned JPA bean.
How do I avoid this behaviour in order to be able to inject @Autowired mock CRUD repositories?
Any help is greatly appreciated!
Aucun commentaire:
Enregistrer un commentaire