ApplicationContext Exception in Test with #WebMvcTest - rest

I Have an Spring Boot Application (1.5.10.RELEASE) which contains a main (SpringBootApplication) like this:
#SpringBootApplication
#Configuration
#EntityScan(basePackages = { "db.modell", "db.modell.base" })
#ComponentScan(basePackages = { "de.gui.test" })
public class SpringBootConsoleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
}
and two REST controllers like the following:
#RestController
#RequestMapping("/as")
public class AController {
#Autowired
private ARepository aRepository;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Collection<A>> getAs() {
return new ResponseEntity<>(orgtFarbeRepository.findAll(), HttpStatus.OK);
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<A> getA(#PathVariable long id) {
A a = ARepository.findOne(id);
if (party != null) {
return new ResponseEntity<>(ARepository.findOne(id), HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
}
Furthermore I have a single test like this:
#RunWith(SpringRunner.class)
#WebMvcTest(AController.class)
public class AControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ARepository ARepository;
#Test
public void firstTest() throws Exception {
A a = new aFarbe();
a.set....
when(ARepository.findAll()).thenReturn(Collections.singleton(a));
mvc.perform(
get("/as")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
)
.andExpect(status().isOk());
}
}
The repositories look like this:
public interface ARepository extends CrudRepository<A, Long>
{
Collection<A> findAll();
}
public interface BRepository extends CrudRepository<B, Long>
{
Collection<B> findAll();
}
A and B them self are JPA annotated classes. The whole application contains access to a database..
Furthermore I have a Service like this:
#Service
public class XService {
private static final Logger LOGGER = LoggerFactory.getLogger(XService.class);
#Autowired
private ARepository aRepository;
#Autowired
private BRepository bRepository;
...
}
The XService is not used via #Autowire or so (Just need to remove that):
So I try to run the AControllerTest I get the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
.. .. at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'XService': Unsatisfied dependency
expressed through field 'BRepository'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
.. .. at
org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 26 more Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 44 more
My assumption is that during the test more context is started than it should. The question is how can I prevent that? Which means only to start the context for the AControler and nothing more? I thought that based on the #WebMvcTest(AController.class) it should be limited already which looks like that it was not the case...

The referenced answer does not really answered my question but a in the context a hint gave me the solution. This means in consequence to add the following to my test:
so I have to add #OverrideAutoConfiguration(enabled=true):
#RunWith(SpringRunner.class)
#WebMvcTest(OrgtFarbenController.class)
#OverrideAutoConfiguration(enabled=true)
public class AControllerTest {
...
}

Related

Repository autowired returning null

I want to make a application with Spring boot on back-end and Swing on front-end. I need to use a repository autowired on my service class, how to make it when i need to instantiate the service class?
I already tried change the repository to BeanFactory, tried to change the location of the files but i can't escape! I need to instantiate the Service class and autowired doesn't work with this.
I have a Model called Permission.
Repository (PermissionRepository.java):
#Repository
public interface PermissionRepository extends JpaRepository<Permission, Long>{
Optional<Permission> findByDescription(String description);
}
Service (PermissionService.java):
#Autowired
BeanFactory beanFactory;
public List<Permission> loadAll() {
return this.beanFactory.getBean(PermissionRepository.class).findAll();
}
Use (BasicOperations.java):
public static void initialPermission() {
try {
if (new PermissionService().loadAll().isEmpty()) {
//logics
}
} catch(Exception e) {
...
}
}
I expect a List, java.util.List but, the error is a nullPointer on my autowired repository
Stack:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.riTrap.service.PermissionService.loadAll(PermissionService.java:20)
You should use autowired instead of new PermissionService. You use loadAll to check if the database contains elements. If the database is big, this approach can damage your application. Suggestion : use count instead
#Service
public class PermissionService {
#Autowired
PermissionRepository permissionRepository;
public List<Permission> loadAll() {
return permissionRepository.findAll();
}
public boolean isEmpty() {
return permissionRepository.count() == 0L;
}
}
If you need to initialize the bean before usage, you can use the constructor :
#Service
public class BasicOperations {
#Autowired
public BasicOperations(PermissionService permissionService){
if(permissionService.isEmpty()){
//DO STUFF
}
}
}

Using embedded MongoDB in Spring JUnit #WebMvcTest

I'm currently using MongoDB in my Spring application. Since I added Mongo my endpoint tests no longer work due to the following error:
No qualifying bean of type 'xxx' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
The repository which I Autowire in a controller is as follows:
private final RuleRepository ruleRepository;
#Autowired
public TestController(RuleRepository ruleRepository) {
this.ruleRepository = ruleRepository;
}
I assume that this has to do with Mongo and the fact that I currently use AutoConfiguration for it. For the test I added the Flapdoodle Embed Mongo dependency, which seems to be used for testing purposes in a lot of examples, to my pom.xml with the scope set to test:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>2.0.3</version>
<scope>test</scope>
</dependency>
My test class looks like this:
RunWith(SpringRunner.class)
#WebMvcTest(value = RouteController.class, secure = false)
#ActiveProfiles("test")
public class TestControllerEndpointTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private RuleRepository ruleRepository;
#Before
public void setupTests() {
//Setup for the tests
}
//Actual tests
}
I also created a Configuration class for the Mongo Test Database, but I don't know how to correctly register it:
#Configuration
#Profile("test")
public class TestMongoConfig {
#Autowired
private MongoProperties properties;
#Autowired(required = false)
private MongoClientOptions options;
#Bean(destroyMethod = "close")
public Mongo mongo(MongodProcess mongodProcess) throws IOException {
Net net = mongodProcess.getConfig().net();
return new MongoClient(net.getServerAddress().getHostName(), net.getPort());
}
#Bean(destroyMethod = "stop")
public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException {
return mongodExecutable.start();
}
#Bean(destroyMethod = "stop")
public MongodExecutable mongodExecutable(MongodStarter mongodStarter, IMongodConfig iMongodConfig) throws IOException {
return mongodStarter.prepare(iMongodConfig);
}
#Bean
public IMongodConfig mongodConfig() throws IOException {
return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();
}
#Bean
public MongodStarter mongodStarter() {
return MongodStarter.getDefaultInstance();
}
}
How do I get an endpoint test that is annotated with #WebMvcTest to use the embedded Mongo database?
After banging our heads for a while we found the #AutoConfigureDataMongo annotation.
import org.springframework.boot.test.autoconfigure.data.mongo.AutoConfigureDataMongo;
#RunWith(SpringRunner.class)
#WebMvcTest(value = SampleController.class, secure = false)
#AutoConfigureDataMongo
public class SampleControllerTest {
Just annotate your controller with it and you should see org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo logs when running this controller tests.

UnsatisfiedDependencyException in SpringMVC and MongoDB project

I'm working on a Spring MVC and MongoDB backed application.
My api is working fine,but i would like to create an integration test with Fongo in order to test saving a file and after getting this file by my services.
I have already tried, but when i added #Autowired in my Service class, it returned an UnsatisfiedDependencyException. My test fixture class is the following:
#ActiveProfiles({"test"})
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
locations = {
"classpath*:config/servlet-config.xml",
"classpath*:config/SpringConfig.xml"})
#WebAppConfiguration
public class IntegrationTest {
#Autowired // returns UnsatisfiedDependencyException
private FileService fileService;
#Before
#Test
public void setUp() throws IOException {
Fongo fongo = new Fongo("dbTest");
DB db = fongo.getDB("myDb");
}
#Test
public void testInsertAndGetFile() throws IOException{
//create a file document in order to save
File file = new File();
file.setId("1");
file.setFileName("test1");
file.setVersionId("1");
//save the file
String id = fileService.storeFile(file);
//get the file
File fileDocument= fileService.getFileById("1");
//check if id is the file id which is expected
assertEquals(fileDocument.getId(), "1");
}
}
and i am receiving this log message:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.ots.openonefilesystem.integration.IntegrationTest': Unsatisfied dependency expressed through field 'fileService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [com.myproject.service.FileService]: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [com.myproject.service.FileService]: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I'm using xml configuration.
How can i solve my testing error? In my service class FileService i have put #Service, however it seems that Spring expected at least 1 bean which qualifies as autowire candidate.
Also if i remove the #Autowired, the log returns NullpointerException when saving of getting the file,as it was expected.
PS: I use springFramework 4.3.3.RELEASE, spring-data-mongodb 1.9.5.RELEASE
Thank you in advance!
I had to configure Mock Database (Fongo), in order to #Autowired FileService. This, I made it via #ContextConfiguration(classes = {MockDatasourceConfig.class})
So, the correct test fixture class is the following:
#ActiveProfiles({"test"})
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MockDatasourceConfig.class})
#WebAppConfiguration
public class IntegrationTest{
#Autowired
private FileService fileService;
#Test
public void testInsertAndGetFile() throws IOException{
//create a file document in order to save
File file = new File();
file.setId("1");
file.setFileName("test1");
file.setVersionId("1");
//save the file and return his id
String id = fileService.storeFileGeneral(file);
//get the file
FileDocument fileDocument= fileService.getFileById(id);
//check that the file isn't null
assertNotNull(fileDocument);
//check if id is the file id which is expected
assertEquals(fileDocument.getId(), id);
assertEquals(fileDocument.getFileName(), "test1");
}
}
and the MockDatasourceConfig class is the following:
#Profile({"test"})
#Configuration
#PropertySource("classpath:mongo.properties")
#ComponentScan(basePackageClasses = {File.class})
#EnableMongoRepositories(basePackageClasses = RepositoryPackageMarker.class)
public class MockDatasourceConfig extends AbstractMongoConfiguration {
#Autowired
Environment env;
#Override
protected String getDatabaseName() {
return env.getProperty("mongo.dbname", "myDb");
}
#Override
public Mongo mongo() throws Exception {
return new Fongo(getDatabaseName()).getMongo();
}
#Bean
public GridFsTemplate gridFsTemplate() throws Exception {
return new GridFsTemplate( mongoDbFactory(),mappingMongoConverter());
}
}
P.S: With helpful advice of #M.Deinum

How can I override "ribbonServerListFilter"

I want to be able to override the default Spring Cloud 'ribbonServerListFilter' implementation. I have read the docs but I always get an error regarding a bean it cannot find (IClientConfig).
So I have a simple class like:
#Configuration
public class FooConfiguration {
#Bean
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
MyListFilter filter = new MyListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
}
and:
#Configuration
#RibbonClient(name = "foo", configuration = FooConfiguration.class)
public class TestConfiguration {
}
But then at runtime I get:
org.springframework.beans.factory.UnsatisfiedDependencyException: \
Error creating bean with name 'ribbonServerListFilter' defined in class path \
resource [FooConfiguration.class]: Unsatisfied dependency expressed through \
constructor argument with index 0 of type \
[com.netflix.client.config.IClientConfig]: : No qualifying bean of type \
[com.netflix.client.config.IClientConfig] found for dependency
So what am I doing wrong?
This is with Spring Boot 1.3.1.RELEASE.
Thanks in advance.
Henry
UPDATE:
Adding full source after Dave's comments.
package com.domain1;
...
#Configuration
public class FooConfiguration {
#Bean
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
System.out.println("My ribbonServerListFilter will be used");
MyListFilter filter = new MyListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
}
package com.domain1;
...
public class MyListFilter extends ZonePreferenceServerListFilter {
#Override
public List<Server> getFilteredListOfServers(List<Server> servers) {
System.out.println("This is my version");
return super.getFilteredListOfServers(servers);
}
}
And the main application in a different package:
package com.domain2;
...
#Configuration
#RibbonClient(name = "foo", configuration = FooConfiguration.class)
public class TestConfiguration {
}
package com.domain2;
...
#Component
#Configuration
public class Runner implements CommandLineRunner {
#Autowired
private DiscoveryClient discoveryClient;
#Autowired
private LoadBalancerClient loadBalancer;
public void run(String... strings) throws Exception {
System.out.println("all");
for (ServiceInstance s : discoveryClient.getInstances("service")) {
System.out.println(s.getHost() + ":" + s.getPort());
}
System.out.println("from lb");
ServiceInstance instance = loadBalancer.choose("service");
System.out.println(instance.getHost() + ":" + instance.getPort());
}
}
package com.domain2;
...
#EnableDiscoveryClient
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
So in the second test when calling 'loadBalancer.choose' I expected my code to be called.
You have to make sure your FooConfiguration is not component scanned. Put it in a separate package not under the main application, or don't use #ComponentScan.

Morphia, Embed Mongo and Spring. Address already in use

I am trying use MongoDB, Morphia and Spring and test it, so I started use Embedded Mongo.
When I had only one DAO to persist I did not had any problem with my tests, however, in some cases I needed use more than one DAO, and in that cases my injected Datasore give me an problem: addr already in use.
My Spring Test Database Configuration is this:
#Configuration
public class DatabaseMockConfig {
private static final int PORT = 12345;
private MongodConfigBuilder configBuilder;
private MongodExecutable mongodExecutable;
private MongodProcess mongodProcess;
#Bean
#Scope("prototype")
public MongodExecutable getMongodExecutable() {
return this.mongodExecutable;
}
#Bean
#Scope("prototype")
public MongodProcess mongodProcess() {
return this.mongodProcess;
}
#Bean
public IMongodConfig getMongodConfig() throws UnknownHostException, IOException {
if (this.configBuilder == null) {
configBuilder = new MongodConfigBuilder().version(Version.Main.PRODUCTION).net(new Net(PORT, Network.localhostIsIPv6()));
}
return this.configBuilder.build();
}
#Autowired
#Bean
#Scope("prototype")
public Datastore datastore(IMongodConfig mongodConfig) throws IOException {
MongodStarter starter = MongodStarter.getDefaultInstance();
this.mongodExecutable = starter.prepare(mongodConfig);
this.mongodProcess = mongodExecutable.start();
MongoClient mongoClient = new MongoClient("localhost", PORT);
return new Morphia().createDatastore(mongoClient, "morphia");
}
#Autowired
#Bean
#Scope("prototype")
public EventDAO eventDAO(final Datastore datastore) {
return new EventDAO(datastore);
}
#Autowired
#Bean
#Scope("prototype")
public EditionDAO editionDAO(final Datastore datastore) {
return new EditionDAO(datastore);
}
}
And my DAO classes are similar to that
#Repository
public class EventDAO {
private final BasicDAO<Event, ObjectId> basicDAO;
#Autowired
public EventDAO(final Datastore datastore) {
this.basicDAO = new BasicDAO<>(Event.class, datastore);
}
...
}
My test class is similar to that:
#ContextConfiguration(classes = AppMockConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class EventDAOTest {
#Autowired
private EventDAO eventDAO;
#Autowired
private MongodExecutable mongodExecutable;
#Autowired
private MongodProcess mongodProcess;
#Rule
public ExpectedException expectedEx = ExpectedException.none();
#After
public void tearDown() {
this.mongodProcess.stop();
this.mongodExecutable.stop();
}
...
}
I use prototype scope to solve problem with singleton and make sure that my mock database is clean when I start my test, after that I stop mongod process and mongod executable.
However since I need use more than one DAO I receive that error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'editionDAO' defined in class br.com.mymusicapp.spring.DatabaseMockConfig: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.mongodb.morphia.Datastore]: :
Error creating bean with name 'datastore' defined in class br.com.mymusicapp.spring.DatabaseMockConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.mongodb.morphia.Datastore]:
Factory method 'datastore' threw exception; nested exception is java.io.IOException: Could not start process: ERROR: listen(): bind() failed errno:98 Address already in use for socket: 0.0.0.0:12345
2015-01-04T01:05:04.128-0200 [initandlisten] ERROR: addr already in use
I know what the error means, I just do not know how can I design my Configuration to solve that. As last option I am considering install a localhost MongoDB just for tests, however I think could be a better solution
That is based on the embedded mongod by flapdoodle, right?
If you want to run multiple tests in parallel (could be changed via JUnit annotations, but it's probably faster in parallel), you cannot use a single, hardcoded port. Instead, let the embedded process select an available port automatically.