Running Spring integration tests with #NoRepositoryBean with no #Repository implementation - java

I have a situation where I have a few modules, with the primary module being datastore agnostic. There are child modules that depend on the primary module with repository implementations for JPA and Mongo.
Core-Module - All business logic, #NoRepositoryBean interfaces
Core-Mongo - Dependent on Core-Module with Mongo repositories/domain
Core-JPA - Dependent on Core-Module with JPA repositories/domain
Essentially, what I'd like to do is have integration tests in Core-Module use an H2 database to perform the tests and not be dependent on a #Repository implementation.
I realize I could make test-only #Repository interfaces, and that may be the route I have to go, but I'm wondering if there's a simpler way. Essentially, is there a way to "instantiate" a #NoRepositoryBean in tests or some other simple way to do this without having to declare test only repositories?

I just checked this interest question. I marked in my test project UserRepository by #NoRepositoryBean, after that in test i unable to autowired it. But in documentation spring-docs i found java creation repositories process description, and it's works perfect. Just before test create required repositories.
Piece of test code example:
private UserRepository userRepository;
#Autowired
private EntityManager entityManager;
#Before
public void init() {
JpaRepositoryFactory factory = new JpaRepositoryFactory(entityManager);
userRepository = factory.getRepository(UserRepository.class);
}

Related

Best Practises of #Repository in Spring boot framework

I have a Spring boot application which has a UserRepository but I have not annotated that repository with #Repository but still my application works fine.
Why #Repository annotation is optional in Spring boot and what is the best practise that should we annotate it or not in repository classes.
It is working because spring will scan the class path and identify given class is repository (DAO) based on the imports, when use #Repositary spring context know how to handle expections like re-throw to pre defined methods ..etc, and also this annotation help readability of the code.
For #Repository annotation even if you haven't mentioned Spring recognizes the repositories by the fact that they are extending Repository interfaces like JPARepository or CrudRepository.
So, it's not mandatory to mention annotation, you can check in your code whether you have mentioned #EnableJpaRepositories("packages") above Main class or not. That might also be one of the reasons why it is working.
As per best practices for annotations, they have a purpose to fulfill, #Repository is important from a database connection perspective, where it has lots of proper exceptions throw, or pre-defined methods.
If you do not use the proper annotations, you may face commit exceptions overridden by rollback transactions. You will see exceptions during the stress load test that is related to roll-back JDBC transactions.
For more clarity have a look at this post
I assume you have somewhere implicitly or explicitly a EnableJpaRepositories annotation which scans all Spring repositories and your repositories are extending CrudRepository or other Spring Data base classes.
The annotation is only needed when defining you own repositories without using Spring Data mechanism. Note, that Repository is just a special Component, latter should also do it to have DI enabled, so this is more for better recognizing the purpose of the class.
#Repository is used to indicate interface that extends a jpa repository, for example. Notice in the example below, the interface extends the Beer class and the BeerQueries query interface.
package com.algaworks.brewer.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.algaworks.brewer.model.Beer;
import com.algaworks.brewer.repository.helper.beer.BeersQueries;
#Repository
public interface Beers extends JpaRepository<Beer, Long>, BeersQueries {
}

How can I do CRUD operations through CrudRepository in Spring?

I'm working with PostgresSQL and I have the following interface:
#Repository
public interface ExampleRepository extends CrudRepository<ExampleEntity, Long> { }
Then I try to get the bean:
ExampleRepository repository = ctx.getBean(ExampleRepository.class);
Of course, I can't do that, because there's no implementation and eventually I get
NoSuchBeanDefinitionException: No qualifying bean of type 'ExampleRepository'
I know this is a wrong approach, but since I'm not enough experienced, I've got no idea how I can communicate with my database. Any example I searched only explained how to implement services & controllers in order to interact with db through Browser. But I want to do CRUD operation inside the java code.
Could anyone explain it to me? Any related sources would also be fine.
I am not sure how you are getting context (ctx) here.
But the common approach is #Repository is not needed instead, #EnableJPARepositories should be used in the #Configuration file. Then use #Autowired to inject the repository into your service class (where you want to execute operation from your repository bean)
You can refer below link for more details
https://mkyong.com/spring-boot/spring-boot-spring-data-jpa/
You don't need to create bean. It will created by the spring framework because you annotated your interface as #Repository .You need only #Autowired in your service class or where do you want to use this reference.
#Autowired
private ExampleRepository exampleRepository;

Spring Data Project - Couchbase Integration

I went over the below tutorials for using couchbase db via Spring
http://projects.spring.io/spring-data-couchbase/#quick-start
I see the below auto wiring in service class. UserRepository is an interface. I assume there should be an implementation which implements this interface and is exposed a bean. I don't see any class implementing this interface or being exposed as a bean. Is it possible to help in explaining how this works?
#Autowired
public MyService(UserRepository userRepository) {
this.userRepository = userRepository;
}
The aim of the Spring-Data project is to create such implementations at runtime for you when you only define interfaces.
It will inspect the packages you configured for scan via reflection and discover xxRepository interfaces in them, at which point it will use a base class provided by the store-specific Spring Data subproject you chose (here Couchbase) to weave together a concrete implementation of xxRepository and inject it.

Spring Data: Service layer unit testing

In my project I'm having trouble doing unit testing. One issue is that just doing an integration test is much faster to write and also tests that the components actually work together. Unit testing novel "algorithms" or so seems much easier. Unit Testing service classes it just feels wrong and useless.
I'm using mockito to mock spring data repository (and hence DB access). The thing is if i tell the mocked repository to return entity A on method call getById it will obviously return that and the service will return it too. Yes, the service does some extra stuff, but very minor things, like load lazy collections (from hibernate). Obviously I don't have any lazy collections (proxies) in a unit test.
Example:
#Test
public void testGetById() {
System.out.println("getById");
TestCompound expResult = new TestCompound(id, "Test Compound", "9999-99-9", null, null, null);
TestCompoundRepository mockedRepository = mock(TestCompoundRepository.class);
when(mockedRepository.findOne(id)).thenReturn(expResult);
ReflectionTestUtils.setField(testCompoundService, "testCompoundRepository",
mockedRepository, TestCompoundRepository.class);
TestCompound result = testCompoundService.getById(id);
assertEquals(expResult, result);
}
hooray, the rest succeeds. What a surprise! Not really no.
Can some one explain to me what I'm doing wrong? Or else what the point of such a test is? I mean I tell to return expResult and then it is returned. Wow. What a surprise! Feels like I'm testing if mockito works and not my Service.
EDIT:
The only benefit I see if some were stupid error happens like leaving an unwanted line there that sets return value to null or something similar stupid. Such cases would be caught by the unit test. Still the "reward-effort" ratio seems bad?
Question might be a bit old but I will put an answer in case someone stumbles across.
I'm using Mockito and JUnit.
AccountRepository is a plain spring data repository extending JPARepository.
Account is a plain JPA entity.
To test your services and mock Spring Data repositories, you need something like below.
package foo.bar.service.impl;
import foo.bar.data.entity.Account;
import foo.bar.data.repository.AccountRepository;
import foo.bar.service.AccountService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest {
#Mock
private static AccountRepository accountRepository;
#InjectMocks
private static AccountService accountService = new AccountServiceImpl();
private Account account;
#Test
public void testFindAccount() {
Integer accountId = new Integer(1);
account = new Account();
account.setId(accountId);
account.setName("Account name");
account.setCode("Accont code");
account.setDescription("Account description");
Mockito.when(accountRepository.findOne(accountId)).thenReturn(account);
Account retrivedAccount = accountService.findAccount(accountId);
Assert.assertEquals(account, retrivedAccount);
}
}
One of the reasons I like testing my Spring Data repositories is to test that I have defined my JPA mappings correctly. I do not use a mocking framework for these tests, I use the Spring Test framework which actually bootstraps the container allowing me to autowire the actual repository into the Junit test so that I may execute tests against it.
I agree with your thoughts that mocking the repository is pretty useless. Since your using Spring I would suggest leveraging the Spring Test framework to perform real tests against your repositories, which can be executed against an embedded database such as H2 in a more unit test based fashion or your actual database implementation such as Oracle or MySql, to conduct more of an integration test. (Execute these against a copy of a development database) These tests will reveal fallacies in your JPA mappings and other items such as improper cascades setup in the database.
Here is an example of one of my tests on GitHub. Notice how the framework actually autowires the repository into the test. The repository also contains an example of how to configure the Spring Test framework, which I have also demonstrated in this blog post.
In conclusion, I do not believe you will receive any of the benefits of testing a repository that I have discussed from using a mock of the repository.
One additional note I wanted to add, is that mocks are not really intended for use in the actual class under test. Their use is for providing required dependencies to a class under test.
You can use this library: https://github.com/agileapes/spring-data-mock
This will mock your repository for you, while allowing you to implement custom functionality for any method as well as your native query methods.
You exactly right. It is clear unit test. And it will never fail (so, it is useless) I think you need at integration test to test real JPA repository with real database (H2 in memory for example) (as I always do).
And it is better to test your services (theirs interfaces). If after some time you will change your storage (to Mongo for example) - you will be able to use your service tests to ensure all works as before.
After some time you will be suprised how many DB\JPA-related problems (constraints, optimistic locks, lazy-loading, duplicate id, some hibernate issues and so on) you find.
Also, try to develop via tests - not just write test after implementation. Instead before creation of new method in service - create test for it, implement service method and only after just recheck it in real application. At least it is much faster to start test than a server.
So, do not create tests to have a lot of them. Find how they may help you.
Usage of mocks for repositories is not good idea. Test how your services work together with Hibernate\JPA\Database. Most part of problems is located beetwen layers.
You can mock the repository and inject it to the service, this is the way; but, if you just instantiate the service with #Mock of repositories, it would be better, if you define the repositories as private final fields in the service and use a constructor of all repositories. That way, if you add another repository to the service, the test will fail and you have to change it, which is the purpose.
Imagine this service:
class OrderService {
private final UserRepository userRepos;
public OrderService(UserRepository userRepos) {
this.userRepos = userRepos;
}
...
}
And this test:
class OrderServiceTests {
#Mock
private UserRepository userRepos;
private OrderService service;
private OrderServiceTests() {
this.service = new OrderService(this.userRepos);
}
}
Now, if we add another dependency to the service:
class OrderService {
private final UserRepository userRepos;
private final AddressRepository addRepos;
public OrderService(UserRepository userRepos, AddressRepository addRepos) {
this.userRepos = userRepos;
this.addRepos = addRepos;
...
}
The previous test will fail because the constructor has changed. If you use #InjectMocks this will not happen; the injection happens behind the curtain and we are not clear what happens; this may not be desirable.
Another thing is, I don't agree that integration test will cover all the cases that unit tests will cover; it may but not always the case. Even the controller can be unit-tested with mocks; after all the tests are meant to cover all the code we have written, so they must be fine-grained; imagine when we follow TTD and we only complete the controller and services level: how we proceed without controller unit testing?
Assuming that we have the below Service class
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeRepository employeeRepository;
#Override
public Employee getEmployeeByName(String name) {
return employeeRepository.findByName(name);
}
}
Test class:
#RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {
#TestConfiguration
static class EmployeeServiceImplTestContextConfiguration {
#Bean
public EmployeeService employeeService() {
return new EmployeeServiceImpl();
}
}
#Autowired
private EmployeeService employeeService;
#MockBean
private EmployeeRepository employeeRepository;
// write test cases here
}
To check the Service class, we need to have an instance of Service class created and available as a #Bean so that we can #Autowire it in our test class. This configuration is achieved by using the #TestConfiguration annotation.
During component scanning, we might find components or configurations created only for specific tests accidentally get picked up everywhere. To help prevent that, Spring Boot provides #TestConfiguration annotation that can be used on classes in src/test/java to indicate that they should not be picked up by scanning.
Another interesting thing here is the use of #MockBean. It creates a Mock for the EmployeeRepository which can be used to bypass the call to the actual EmployeeRepository:
#Before
public void setUp() {
Employee alex = new Employee("alex");
Mockito.when(employeeRepository.findByName(alex.getName()))
.thenReturn(alex);
}
After the setup, we can easily test our service like:
#Test
public void whenValidName_thenEmployeeShouldBeFound() {
String name = "alex";
Employee found = employeeService.getEmployeeByName(name);
assertThat(found.getName())isEqualTo(name);
}
For more in depth knowledge check:
https://www.baeldung.com/spring-boot-testing

How can I make Spring testcontext framework use multiple data sources?

I'm trying to integration test my application with Spring TestContext framework. I have done this by extending AbstractTransactionalJUnit4SpringContextTests, as usual. However, my application has three different data sources (with names like xDataSource, yDataSource, zdataSource), så when I try to run the test, the autowiring of data source in AbstractTransactionalJUnit4SpringContextTests won't work, since it looks for a Data Source with autowire-by-type, but finds three, so it does not know which one to choose.
Is there any way to get Spring TestContext Framework to use three data sources? If so; how?
OK, I figured it out. The answer to this question is twofold. Firstly, extending AbstractTransactionalJUnit4SpringContextTests won't work. This is because it needs a single data source for creating the SimpleJdbcTemplate for verifying stuff with simple JDBC queries in the test. Since I don't use this feature in this test, I could replace extends AbstractTransactionalJUnit4SpringContextTests with the collowing configuration:
#ContextConfiguration(locations = "classpath:applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class
})
#Transactional
public class IntegrationTest {
...
}
The combination of these annotations gives the same setup as extending AbstractTransactionalJUnit4SpringContextTests.
The second part was understanding that since I have three data sources, I also need all three so be referenced by the same PlatformTransactionManager. I have distributed transactions. This is impossible with a DataSourceTransactionManager, so I had to use a JtaTransactionManager.
The AbstractTransactionalJUnit4SpringContextTests class is autowired to a single data source only to allow the convenience of providing an injected JdbcTemplate object. You can override the setDataSource(DataSource dataSource) method from AbstractTransactionalJUnit4SpringContextTests in your test subclass and specify the data source to use like this:
#Resource(name = "dataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
You just have to provide the name of the one data source Spring should use for the jdbcTemplate convenience methods. If extending AbstractTransactionalJUnit4SpringContextTests is more convenient than other methods mentioned above, then you can force it to work by just choosing one of your data sources.
I found these details in Spring Jira ticket #SPR-4634.
You can define one of the data-sources as primary="true" in your xml, and it will be chosen.
If you need all threem then you cannot rely on autowiring - use ReflectionTestUtils to set it manually in your tests.

Categories