How to test database calls with testng in spring boot - java

I have created small web application in spring boot.I am new for TestNG. I am trying to test my services with testng which calls dao for database operations. I am trying to do it using inmemory database HSQL.
Following is my UserService
#Service
class UserServiceImpl implements UserService
{
public void save(User user)
{
userDao.save(user);
}
public User update(user)
{
userDao.update(user);
}
}
Following is my UserTest class
#Test
class UserTest
{
?
}
What is good way to use HSQL to test save and update methods in UserService using TestNG with DataProvider? Please let me know if need some more information regarding question ;)
Your response will be greatly appreciated!!

If you just want to test if the dao is called correctly, mock it with a mocking framework (i'd choose Mockito) and just verify that the correct methods were called by your Service. This is more "unit" like, since you tests reflect the clear separation of dao and service.
If you are interested in real DB communication to create/load instances and so on, you can use an in memory database like h2 and let your dao run against that database. This becomes more of an integration test, but can be useful none the less.
Either way, you would set up a test application context that cares about datasources and mocks.

Acolyte provides a JDBC driver & tools, designed for such purposes (mock up, testing, ...): https://github.com/cchantep/acolyte
It's already used in several open source projects (Anorm, Youtube Vitess, ...), either in vanilla Java, or using its Scala DSL:
handler = handleStatement.withQueryDetection(...).
withQueryHandler(/* which result for which query */).
withUpdateHandler(/* which result for which update */).
// Register prepared handler with expected ID 'my-unique-id'
acolyte.Driver.register("my-unique-id", handler);
// then ...
Connection con = DriverManager.getConnection(jdbcUrl);
// ... Connection |con| is managed through |handler|
Note: I am the author of Acolyte.

Related

Java integration test with fake outbound call

I work on a Java project using Spring framework, JUnit and Mockito.
The application is in the middle of a chain with others application, so it exposes inbound ports (e.g. an HTTP API) to be called and uses outbound ports (e.g. web services and database) to call other apps.
I want to write something like an integration test that should pass through the whole java code from the inbound port to the outbound port, but without doing any call to anything that's outside of the project.
Let's take a very-simple-but-very-concrete example :
We expose an HTTP endpoint to get customers and we call another app to get them.
In the domain : customers are represented by the Customer class.
In the externalapp layer : customers are represented by the CustomerModel class.
In the rest layer : customers are represented by the CustomerDto class.
Thus :
The CustomerSupplierAdapter class gets data from CustomerRepository and does the mapping from CustomerModel to Customer.
The CustomerControllerAdapter class does the mapping from Customer to CustomerDto and returns the data.
Now, I want to test my app by calling the CustomerControllerAdapter's getCustomers(), which will call the real service, which will call the real supplier, which will call a fake repository.
I wrote the following code :
#ExtendWith(SpringExtension.class)
class CustomerIntegrationTest {
#Mock
private CustomerRepository repository;
#InjectMocks
private CustomerControllerAdapter controller;
#BeforeAll
void setupAll() {
CustomerOutboundPort customerOutboundPort = new CustomerSupplierAdapter(repository);
CustomerInboundPort customerInboundPort = new CustomerService(customerOutboundPort);
controller = new CustomerControllerAdapter(customerInboundPort);
}
#Test
void bulkQuery() {
// Given
CustomerModel model = new CustomerModel();
model.setName("Arya Stark");
doReturn(List.of(model)).when(repository).getCustomers();
// When
List<CustomerDto> dtos = controller.getCustomers();
// Then
assertThat(dtos).hasSize(1);
assertThat(dtos.get(0).getName()).isEqualTo("Arya Stark");
}
}
But in this code, I do the "constructor's wiring" by myself in the setupAll() instead of relying on Spring dependency injection. It is not a viable solution because it would be very hard to maintain in real-life context (controller may have multiple services, service may have multiple suppliers, etc).
Actually, I would like to have something like an annotation to set on a CustomerRepository instance to programmatically overload dependency injection. Like : "Hey Spring, if any #Service class needs a CustomerRepository then you should use this fake one instead of the usual concrete implementation" without having to do the wiring by myself.
Is there any way to achieve that using Spring, JUnit, Mockito or anything else ?
If you really want to replace every CustomerRepository in your tests (everywhere!) with a mock, I'd recommend going for a configuration which provides a #Bean, which creates a mocked bean.
#Profile("test")
#Configuration
public class TestConfiguration {
#Bean
#Primary
public CustomerRepository customerRepostiory() {
return Mockito.mock(CustomerRepository.class);
}
}
#MockBean can have negative effects on your test duration as it's quite possible Spring needs to restart it's context.
Alternatively, I'd recommend NOT mocking your repository at all, but instead using either an in memory equivalent (H2) or the TestContainers framework to start the real database for you. Instead of mocking, you insert data into your repository before you start your tests.

#BeforeAll JUnit/spring-boot-test alternative that runs when application context starts

I'm writing a #Repository/#Service integration test that leverages an embedded database. In my test class, I would like to preload my database with some data.
I'm currently using #BeforeEach to load in my sample data, however, this code is run upon each test in my class.
Is there any way that I can load in my test data after Spring application context has loaded, but before any test has been run?
My current approach:
#BeforeEach
public void before() {
repository.save(...); // -> prepopulates repository with sample data
}
#Test
public void testService() {
service.get(...); // -> gathers existing record
}
#Test
public void deleteById() {
service.delete(...); // -> deletes existing record
}
However... with this, I am required to flush out the records after every test. Otherwise any unique constraints can easily be violated.
Rather than using #BeforeEach which is required to run before every test... is it possible to load this in in a #BeforeAll kind of fashion that happens after the spring application context has been loaded?
Is there any way that I can load in my test data after Spring application context has loaded
Basically yes, I think you can do that:
The idea is to load the SQL data when the application context is started or in the process of being started.
For example, spring boot integration with Flyway works this way (the bean of Flyway is created and loaded). So, in theory, you could merely use Flyway with test migrations that will contain all the relevant SQL scripts of test data generation.
How can you do this technically?
Here is one way:
Create a special bean (just like the way it works with Flyway) that would depend on your repository and in post construct save the data:
#Component
public class SqlGenerationBean {
#Autowired
private MyRepository repo;
#PostConstruct
public void init() {
repo.save();
}
}
Another way of doing is to create a listener that will be called upon the application context started and again will call the same repo.save().
In both cases the bean/listener code should not be accessible from production (it's only for tests): so put it somewhere under src/test/java for example
Now once the application context is started you can use a neat trick:
Mark your tests with #Transactional annotation. Spring will wrap the code in an artificial transaction that will be rolled back automatically (even if the test succeeds) so that all the data that you'll modify during the test will be rolled back and basically before each test, you'll have the same state (that is identical to the state of the database when/after the application context starts). Of course, if you use DDL in the test, some databases can't make it a part of transaction but it depends on the database really.
Another interesting point here is that the application context can be cached even between the test cases (created only once), so keep this in mind.
In this case I would just create a constructor for the test class. It will be triggered before everything.
#BeforeEach runs before each tests but after all initialisations .
you can also just use Mockito and mock the result without need to clean and overcomplicate
Just add following snippet to your code. This is just like you can do to detect that Spring application is really started.
#Configuration
public class AppConfig implements ApplicationListener<ApplicationReadyEvent> {
/**
* This is to indicate in the logs when the application has actually started and everything is loaded.
*/
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ApplicationContext context = event.getApplicationContext();
Environment env = context.getEnvironment();
// do what you want on application start
}
}
P.S. For database manipulation in test #Sql is the best candidate as was mentioned in comment.

Does Spring provide stub implementation of JpaRepositories?

I am trying to unit test my Service classes that looks similiar to this:
#Service
public class SomeQueryService {
private final SomeRepository repository;
public SomeQueryService(SomeRepository repository) {
this.repository = repository;
}
public void doSomething() {
// code doing some magic
}
}
SomeRepository is simple repository interface extending JpaRepository interface.
What I want to do is unit test this service to verify whether it is working properly.
I do not want to use mockito to mock repository behaviour instead, I want to have some in-memory implementation (on list or map) that will imitate database behaviour.
Does Spring provide such fake implementations?
I want to avoid making Stub Implementation of such repository by myself as I will be using such tests in many other places.
RealLifeDeveloper has created an MIT-licensed helper-class to do just what you want: implement the repository-interface with a plain-old-java-object that just wraps a Collection, and called it "InMemoryJpaRepository". You will still have to implement some logic yourself1, though it should be easy if your queries are not too complicated.
An article explaining how to do this with example: https://reallifedeveloper.com/creating-in-memory-versions-of-spring-data-jpa-repositories-for-testing/
The repository (which includes other stuff, too) is on github: https://github.com/reallifedeveloper/rld-build-tool
The specific helper-files for creating the inmemory-db are found at https://github.com/reallifedeveloper/rld-build-tools/tree/master/src/main/java/com/reallifedeveloper/tools/test/database/inmemory if you dont want the whole repo.
1 The rule "Don't put logic in tests" exists for a reason and is clearly violated here. However, the well-known and widely-used alternatives mentioned by the other answers, H2-testing and extensive mocking, have their drawbacks too.
The type of testing you are referring to is called "Integration Testing" or "End to end testing" since it tests the whole application or a big chunk of it compared to unit tests that test only one method.
https://www.guru99.com/unit-test-vs-integration-test.html
You should not unit test your repositories, since they are already well tested by the spring team.
Solution:
You can create a test that starts the whole spring container using Spring Boot:
Just create a class in your test folder and annotate it with:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTestClass {
#Test
public void test() {
}
}
You can then configure an embedded database using H2 so that your test does not use the production database, just follow the Spring Boot Database Initialization doc.
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html
PS. You can also create a specific profile using the following annotation on your test class:
#ActiveProfiles("test")
No Spring Data does not provide a fake implementation of that interface.
You'll have to create it on your own or use a mocking framework like Mockito.

How can I query SQL just after transaction open?

Just like in the title. I need to query a specific function on database which will define a few values assigned to the transaction. If it's possible I want to make it a global configuration connected with a specific profile(There are few requests that I do not want to load that function).
Project is build on Java SE 1.7, Spring Boot 1.1.7 and it connects with PostgreSQL database.
Requests are build on 3 layers, SomeClassController(Controller), SomeClassService(Service), SomeClassDB(Repository). On SomeClassDB it connects with database using JdbcTemplate from Spring and performs a CRUD operations. Before any of those operations I want to query a function. And as i mentioned it, I don't want a method that will do the job - I need something like global configuration on TransactionManager?
Maybe I should use TransactionSynchronization with beforeCommit method? But I don't know how to use it globally.
EDIT1: What I can but i don't want to ;):
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
#Service
public class SessionService {
Boolean flag;
public SessionService(){
flag=false;
}
#Value("${appVersion}") String appVersion;
#Value("${appArtifactId}") String appArtifactId;
public void addSession(){
if(!flag){
jdbcTemplate.execute("SELECT add_ses('"+appArtifactId+"','"+appVersion+")");
flag=true;
}
}
public void deleteSession(){
jdbcTemplate.execute("SELECT del_ses()");
}
}
And now I can just call those two methods on start and end of 2nd layer class with #Autowired this class. But I really don't want to do it in that way. Someone, someday will forget about it propagating that 2nd layer SomeClassService class and I want to avoid it.
I hope that will get you closer to my problem.
This could be typical use case of aspects. Have you tried to write an aspect for this? Aspect can be configured to execute some code before and after call of a method in specific package or method decorated by specific annotation. Spring has very nice support for aspects.
Another way is to create a proxy (using java.lang.reflect.Proxy) object which will call your initialization code and then delegate to proxied object.

Testing Hibernate DAO using Junit

I am using a combination of Spring and Hibernate in my project and would like to test the DAO methods like Save and Delete methods.
daoFoundation is a wrapper class created over hibernateSession.
#Override
public String createSubject(Subject subject) {
String subjectId = (String) daoFoundation.save(subject);
return subjectId;
}
This is what I wrote in my JUnit Runs with SpringJunit4ClassRunner
I created the subject object in my SetupMethod.
#Test
public void createSubjectTest(){
subjectDao.createSubject(subject);
assertNotNull(hassSubjectSelection.getId());
}
Is this sufficient or do I need to write anything additional in my test class?
The easiest way is to import your Spring application context, autowire in the DAO's you want to test and then mark either your test methods or the entire class as #Transactional. This will create a Hibernate session, run your test and then automatically roll back the transaction so you don't effect your database state with your tests.
Have a look at how to run unit tests with Spring here. You can get Spring to create your entire application context using the #ContextConfiguration annotation. So if you create your database using an XML file called database-servlet.xml then you would annotate
#ContextConfiguration(locations={"classpath:/database-servlet.xml"})
public class Test()
You can use the annotation #RunWith(SpringJUnit4ClassRunner.class) to use functionality of the Spring TestContext Framework with your unit tests. This allows you to do things like declare expected exceptions that should be thrown, run timed tests, repeat test runs X times and a bunch of other cool stuff.
Basically to get this working, your test class should look similar to the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={YOUR APP CONTEXT FILES HERE AS A COMMA SEPARATED LIST})
public class Test(){
#Autowired
private YourDAO yourDAO;
#Test
#Transactional
public void testSave(){
//Test save method here. Any database changes made here will be
//automatically rolled back when the test finishes.
}
Let me know if that works or not.
The best way to test your dao layer is to use the spring jdbctemplate to write data to your database the test your get and delete methods. Then in the #after delete the records you wrote. Then use hibernate to write to your database and use jdbctemplate to read them back. Then delete your test rows. Anything less and all you are really doing is testing hibernate's caching.

Categories

Resources