What are the things I need to test in Controller Testing, Service Testing and Repository Testing
Example:
In controller testing I should test:
If the endpoint will not work in different HTTP Methods
If the endpoint can receive request
I want to ask suggestions from other devs so I can learn the other goals in testing
I already know some of the parts that needs to be tested but I wanna ask if there are parts that I don't know
Related
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.
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.
I'm looking at Spring REST Docs and wondering if it has the ability to interrogate #RestController methods to produce basic documentation describing a Rest API (methods, http method, parameters, response type)? I believe Springfox Spring/Swagger does that, and would be easier than having to write a test to get that basic info/documentation.
Also, since I don't want to run integration tests in a Production environment, is the Spring RestDocs approach to run your integration tests in a Test environment and then copy the generated docs/snippets into the war so it can be viewed in a Prod environment?
I'm looking at Spring REST Docs and wondering if it has the ability to interrogate #RestController methods to produce basic documentation describing a Rest API
Spring REST Docs is test-driven and deliberately doesn't take the approach of introspecting #RestController methods. You REST API documentation is describing HTTP requests and responses. By being test-driven and working with real or mocked HTTP requests and responses, REST Docs ensures that what you're documenting is what users of your API will be dealing with.
The problem with introspecting #RestController methods is that it's only one small piece of the puzzle. When an HTTP request is received it passes through filters, interceptors, HTTP message conversion etc before it reaches your controller. The same is true in reverse when a response is being sent. Without a complete understanding of everything that happens before your controller's called and everything that happens after your controller returns, the documentation is at risk of being inaccurate.
is the Spring RestDocs approach to run your integration tests in a Test environment and then copy the generated docs/snippets into the war so it can be viewed in a Prod environment
Correct. The documentation is generated once at build time and then typically served as static files from your application. Details of how to do this with Spring Boot are included in the documentation.
This approach has the advantage that none of the code that's involved in creating the documentation is running in production. That reduces your application's footprint, and avoids the possibility of the code that's generating the documentation from causing a problem in production. I believe you can take a similar approach with code-first Swagger tools but, in my experience, it's unusual for people to do so.
Swagger is best choice for me. You cannot do make docs with Spring Rest Docs without integration tests. It's good article reviews rest tools
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.
Is it possible to use MockMvc test code to hit a real instance of a web application?
I really like the MockMvc syntax and after going to the efforts of writing a load of code to test controllers, it seems like a duplication of effort to rewrite what would effectively be the same tests using a different API just so I can make an actual HTTP request.
I've got some situations where my MockMvc tests pass, but then the tested behaviour fails when deployed to a web container. This is normally a configuration or environmental issue, and it'd be nice to be able to repeat the same tests to flush those out.
MockMvc is about testing the Controller Layer and it works like a charm .
I think you need Selenium tests to test against a real, deployed application.
Using webdriver (With phantomjs) guarantees that you have the same ease of use as you get with Spring MVC.
But you will have to rewrite your tests to work with webdriver+phantomjs.