Unit testing for Spring Boot API - spring-boot

I'm developing a Spring Boot Web API, and I'm currently writing the required units tests.
I was wondering : Isn't writing the units tests (JUnit + Mockito) for the controllers sufficient ? Since the controllers are the entrypoint of my application and that all the logic that is implemented within the Service side is called from the exposed API, why do I need to write test for the Service side ?

First of all, if you write your tests to cover "required level of tests" or requirement to "have some tests at all" having the production implementation already done, it is slightly too late. In the majority of cases having tests first, based on your requirements, contract, use case or anything it more optimal approach. Nevertheless, I don't know your situation and the thing you're trying to implement, so treat it as a suggestion and move on to the key thing you are asking about.
Your JUnit (preferably 5) and Mockito tests, which probably use MockMvc are very good unit(-like) tests to cover web communication concerns such as: HTTP request types, content type, encoding, input and output parameters JSON (de)serialization, error handling, etc. They are best to test with the service layer mocked. Thanks to that you can easily cover a lot of web cases without the need to prepare data in a database, etc.
The core logic has to also be tested. Depending what it is, it might be feasible to test it in the unit way (the easiest to write, can cover a lot of - also corner - cases). It could be supplemented with some set of integration tests to verify that it works fine also in integration (Spring Beans, DB, etc.).
If desired, you may also write some E2E test from the web call via (real) HTTP requests through controllers, services to a database/datastore (if any), but I would limit it only to the most important scenarios to use it in your CI/CD pipeline to verify that a deployment finished successfully.
Disclaimer. I've found this approach useful in multiple situations, but definitely in some other circumstances it might be good to change the balance point to better apply testing.

I think you are probably getting confused between unit and Integration tests.
If you are using Mockito you are probably referring to unit tests wherein, the scope of the Test Class should be only the current class.
Any external method calls should be mocked.So in your case the service calls should be mocked in case you are writing unit test for your controller class.
Your Test Suite should contain
Junit for Controller-- To Test the interface contract points like HTTP Method, Request Parameters, Mandatory inputs, Valid Request Payloads.
Junit for all other classes including Service classes- This is to test your application classes core logic
Integration Test- Finally an integration test which can hit your controller endpoints with service classes and rest of the application code functionality.

Related

Is it worth implementing service integration tests in Spring Boot application?

I have come accross multiple articles on integration testing on Spring Boot applications. Given that the application follows three layer pattern (Web Layer - Service Layer - Repository Layer) I have not seen a single article with integration testing the application up to just the service layer (ommiting the web layer) where all the business logic is contained. All of the integration tests seem like controller unit tests - mostly veryfing only request and response payloads, parameters etc.
What I would like however is to verify the business logic using service integration tests. Since the web layer is responsible only for taking the results from services and exchanging them with the client I think this makes much more sense. Such tests could also contain some database state verifications after running services to e.g. ensure that there are no detached leftovers.
Since I have never seen such a test, is it a good practice to implement one? If no, then why?
There is no one true proper way to test Spring applications. A general approach is as you described:
slices tests (#DataJpaTest, #WebMvcTest) etc for components that heavily rely on Spring
unit tests for domain classes and service layer
small amount of e2e tests (#SpringBootTest) to see if everything is working together properly
Spotify engineers on the other hand wrote how they don't do almost any unit testing and everything is covered with integration tests that covered with integration tests.
There is nothing stopping you from using #SpringBootTest and test your service layer with all underlying components. There are things you need to consider:
it is harder to prepare test data (or put system under certain state), as you need to put them into the database
you need to clean the database by yourself, as (#SpringBootTest) does not rollback transactions
it is harder to test edge cases
you need to mock external HTTP services with things like Wiremock - which is also harder than using regular Mockito
you need to take care of how many application contexts you create during tests - first that it's slow, second each application context will connect to the database, so you will create X connections per context and eventually you can reach limits of your database server.
This is borderline opinion-based, but still, I will share my take on this.
I usually follow Mike Cohn's original test pyramid such as depicted below.
The reason is that unit tests are not only easier to write but also faster and most likely cover much more than other more granular tests.
Then we come across the service or integration tests, the ones you mention in your question. They are usually harder to write simply because you are now testing the whole application and not only a single class and take longer to run. The benefit is that you are able to test a given scenario and most probably they do not require as much maintenance as the unit tests when you need to change something in your code.
However, and here comes the opinion part, I usually prefer to focus much more on writing good and extensive unit tests (but not too much on test coverage and more on what I expect from that class) than on fully-fledged integration tests. What I do like to do is take advantage of Spring Slice Tests which in the pyramid would be placed between the Unit Tests and the Service Tests. They allow you to focus on a specific class (a Controller for example) but they also allow you to test some integration with the underlying Spring Framework or infrastructure. This is for me the best of both worlds. You can still focus on a single class but also test some relevant components of your application. You can test your web layer with #WebMvcTest or #WebFluxTest (so that you can test JSON deserialization and serialization, bean validation, etc...), or you can focus on your persistence layer with #DataJpaTest, #JdbcTest or #DataMongoTest (so that you can test the actual persistence and retrieval of data).
Wrapping up, I usually write a bunch of Unit Tests and then web layer tests to check my Controllers and also some persistence layer tests against a real database.
You can read more in the following interesting online resources:
https://martinfowler.com/articles/practical-test-pyramid.html
https://www.baeldung.com/spring-tests

What is correct way writing Integration test in Spring or Spring Boot based application

I am writing code for Spring Boot Rest application which interact with DB using Spring JPA.
My app have 3 main layers Controller,Service,Repository and it have CURD operations.
I want to follow TDD approach. My question is how do I populate data for each VERB implementation.
For example I am starting with CREATE impl and implemented CREATE flow with Controller,Service,Repo etc. Now to implement PUT,GET,DELETE I need to populate data while writing my tests. For this purpose I used Injecting Repository in my Integration test class and loaded data before my actual Test Runs or Used DataLoader with CommandLineRunner Implemention to pre-populate the data. Buy my collegue insisted me I should never use Repository in Integration Test class for populating data instead should User Service class bean and call CREATE implementation for required data population.
Is it any best practice or guideline documentation to design Integration Test and Unit Test?
And main question did we use Repository in Integration Test class for populating data or not?
The main motive of writing integration testing is to test the interface between two software units or modules. It focuses on determining the correctness of the interface. That means you should test your application in the sense of whether your app can be integrated into other software or not. In that case, your beans like repositories or services are not injectable or applicable from the other software except your endpoints that you are exposing through controllers.
Writing Integration Test
There are a couple of things you should consider before writing your integration test such as the scope of your test cases, scenarios of each endpoint, tools/libraries to write the tests, etc.
You can use something like RestTemplate or MockMvc to invoke HTTP requests(POST, PUT, CREATE, DELETE). For example, make a GET request with RestTemplate,
#Autowired
private RestTemplate restTemplate;
#Test
void givenYourObjectTypes_whenGetYourObjectTypes_thenStatus200()
ResponseEntity<YourObjectType> response = restTemplate.getForEntity(requestUrl, YourObjectType.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
My question is how do I populate data for each VERB implementation.
There are annotations called BeforeEach and BeforeAll, you can use either of them in a setup method to populate your data
Is it any best practice or guideline documentation to design Integration Test and Unit Test?
There are a lot of documentations you can find out in google. But once you grasp the core concept of the test, you will be intimated to workaround. Still, I would refer to you to have a look at an article by Martin Fowler on Integration Test (It's my personal preference).
And the main question did we use Repository in Integration Test class for populating data or not?
Populating data using repositories is not the recommended approach. Instead, I suggest you use CREATE API to populate data which would be a real scenario while integrating with other services/UI/modules/software.
Moreover, You could try H2 dependency with scope test while testing your application which makes it faster to perform the test cases. But note that it is only applicable if you are using SQL database.

Why are there different types of integration tests in Spring Boot

does anybody know why the Spring Boot Guide includes two different types of integration tests? (https://github.com/spring-guides/gs-spring-boot#add-unit-tests)
One with TestRestTemplate and one with MockMvc dependency? In each test type spring boot bootstraps the test environment. So what is the reason for this separation?
When you use MockMvc you are testing an instance of your application in which the HTTP request cycle has been mocked. So, the test scope here is just the MVC aspects of your application. I don't think this would be typically labelled an "integration test", instead it is closer to a unit test (albeit its scope is considerably larger than a single class).
When you use TestRestTemplate you are testing a real instance of your application i.e. you are 'springing up' an entire application context and invoking it as an external actor. This is typically referred to as an "integration test" and it is likely to be the closest test to your actual usage.
Now, since a 'full stack' integration test invoked via TestRestTemplate can provide a superset of the coverage provided by a MockMVC test you might be wondering why you would bother with a MockMVC test. If so, then I think this is a question of ...
Test scope; MockMVC test cases are typically quicker and easier to fire up (since they use less of your application context) than a full integration test. In addition, since they use less of your appolication context you may not have to work as hard to mock out any aspects of your real application context which don't play well in a test.
Ease of use; MockMVC comes with static helpers for asserting HTTP status, interrogating and asserting against JSON responses etc. Of course YMMMV but for many people these faciliate an ease of development and help deliver readable test cases.
In practice, you'll perhaps want to use a combination of both approaches:
MockMVC tests for detailed testing of the entire controller layer including all mappings, happy and sad paths for all invocations and deep assertions on HTTP status codes, content bodies etc
TestRestTemplate tests for the main flows expressed from the users perspective e.g. Save a new Foo, Search for all Foos, Submit an invalid Foo update etc with assertions focussing on the bits which your users see/are interested in.

Unit testing in spring mvc

If I want to unit test my dao classes in spring would I just call my service methods and test those or would you test the service methods separately to the actual dao methods?
Also should I mock the dao calls or actually use an in memory database like H2? I see that as more of an integration test although some tutorials do this, or would a standard approach be to test with mock database objects for the service tests and use H2 when testing the dao calls?
Finally.. My application has a rest API which is called from the web front end using the Spring rest template and so only the API web app accesses the database.
Would I test the rest methods in each web app using mocked objects and then Start a tomcat instance and integration test between the 2 apps? If I used tomcat and ran integration tests between the apps would connect up a database or mock objects in the API app?
Testing the rest calls from the web app relies really on how the API app's rest method responds so is this even worth testing in isolation?
I find unit testing quite confusing as some of it seems almost to be integration testing.
Does it matter if you run integration tests against H2 in memory but then in reality I would be using MySQL?
Trying to answer your questions in the order asked...
For unit testing DAO methods, you should test the actual DAO classes directly with a database in a known state. H2 is great for this, since you can run it without setting up MySQL for each test. Utilizing setup methods with the #Before annotation is great to make sure that the database will respond in expected ways.
For unit testing Service classes, you should mock the DAO classes, so that they will always behave in expected ways. If you use your service and DAO classes with actual data, you are now running integration tests, by testing multiple layers simultaneously. Both have their value, though is generally best to unit test before integration testing, to make sure each component is functioning.
The same goes for testing your controller, you should unit test it and mock the service classes, and then perform integration tests with mock requests to test request/response scenarios. Again, with this test setup you are now testing many layers and classes simultaneously. This is great, because it gives you a good idea of how your application will function in reality, but is not useful for isolating bugs.
H2 and MySQL obviously are not the same, and don't share all the same functionality, so you can't say with 100% confidence that an H2 test will pass in MySQL, but if you are just testing standard CRUD operations, it should do the trick.

In TDD, why OpenEJB and why Arquillian?

I'm a web developer ended up in some Java EE development (Richfaces, Seam 2, EJB 3.1, JPA). To test JPA I use hypersonic and Mockito. But I lack deeper EJB knowledge.
Some may argue that we should use OpenEJB and Arquillian, but for what?
When do I need to do container dependent tests? What are the possible test scenarios where I need OpenEJB and Arquillian?
Please enlighten me :)
There are two aspects in this case.
Unit tests. These are intended to be very fast (execute the whole test suite in seconds). They test very small chunks of your code - i.e. one method. To achieve this kind of granularity, you need to mock the whole environment using i.e. Mockito. You're not interested in:
invoking EntityManager and putting entities into the database,
testing transactions,
making asynchronous invocations,
hitting the JMS Endpoint, etc.
You mock this whole environment and just test each method separately. Unit tests are fine-grained and blazingly fast. It's because you can execute them each time you make some important changes in code. If they were more complex and time-consuming, the developer wouldn't hit the 'test' button so often as he should.
Integration tests. These are slower, as you want to test the integration between your modules. You want to test if they 'talk' to each other appropriately, i.e.:
are the transactions propagated in the way you expect it,
what happens if you invoke your business method with no transaction at all,
does the changes sent from your WebServices client, really hits your endpoint method and it adds the data to the database?
what if my JMS endpoint throw an ApplicationException - will it properly rollback all the changes?
As you see, integration tests are coarse-grained and as they're executed in the container (or basically: in production-like environment) they're much slower. These tests are normally not executed by the developer after each code change.
Of course, you can run the EJB Container in embedded mode, just as you can execute the JPA in Java SE. The point is that the artificial environment is giving you the basic services, but you'll end with tweaking it and still end with less flexibility than in the real container.
Arquillian gives you the ability to create the production environment on the container of your choice and just execute tests in this environment (using the datasources, JMS destinations, and a whole lot of other configurations you expect to see in production environment.)
Hope it helps.
I attended Devoxx this year and got a chance to answer the JBOSS dudes this question.
Some of the test scenarios (the stuff i managed to scribble down):
Configuration of the container
Container integration
Transaction boundaries
Entity callback methods
Integration tests
Selenium recordings

Resources