I have a Web API controller action that takes a quite complex object as an argument. It's to be passed to the webservice as JSON, of course, and is supposed to deserialize into an instance of a C# class.
I have unit tests in the business layer to convince me that JSON serialization/deserialization of the class in question works as expected.
And I have C# unit tests running against the Web API controllers, passing instances of this class into the actions, to ensure that if the controller actions have the right behavior, given the correct objects.
My problem: these objects are complicated enough that constructing improper JSON isn't going to be easy. My intent is to create some convenience functions, in Javascript, to aid in that construction, and I'd like to have unit tests to make sure that they work, and unit tests to ensure that properly-formatted JSON is deserialized into the target class as expected.
That means I need to create, in my VS2013 solution, a way to run javascript, both as self-contained unit tests, and as calls against my Web API webservice.
Any suggestions as to what tooling would work best for that?
I'd really like something that can be contained within Visual Studio, so that it can be configured as an MsBuild target. (Would make the guys who deal with the Continuous Integration configuration much happier.)
Related
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
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.
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.
I've a java application which has multiple modules - (GWT-)RPC services, perf-library, remote-client (All java code written/owned by my team). The perf-library contains Spring AOP aspects related code and it's primarily used to push intercepted method logs to a data store. Now, perf-library is dependent on another remote-client which actually maintains a queue and handles the job of pushing logs to the data store. So, in a way, perf-library just delegates the task to remote-client.
The business logic code calls intercepted methods which have AOP logic and hence there is a dependency on remote-client. Obviously, I don't want to connect to the remote-client from within unit tests. I think I need to mock the implementation of method push() which connects to remote-client. What I'm unable to figure out is how to use the mock implementation for the business logic code package unit tests.
To clarify things, I've modules like this -
RPC service module - e.g. method login() is intercepted.
perf-library - Has aspects (to intercept methods like login()) and implementation to call remote-client
remote-client - Push data to some data-store
Now, for writing the unit tests for RPC service methods, how do I get the mock implementation of push() as it is internal to perf-library. Let's say, I've an interface LogClient (having method push()) which is implemented by two classes (one for production and another for test). I can use this Test implementation for unit tests of perf-library itself, but how do I make the RPC unit tests use it. I'm new to Spring, so not sure if this can be done easily with Spring or anything else. Any help will be nice.
Note: We're using Spring for maintaining beans and DI.
Not sure exactly how but Mockito can be a good choice.
Check this link for details.
I am implementing a Service Contract for WCF Service.
As per TDD I wrote a test case to just pass it using hardcoded values.
After that I started to put real logic into my Service implementation. The actual logic relies on 3-4 external service and database.
What should I do to my original test case that I wrote ?
If i Keep it same in order to make test pass it will have to call several other external services.
So I have question in general what should I do if I write a test case for a Business Facade first using TDD and later when I add real logic, if it involves external dependency.
Utilize a mocking framework (with dependency inversion or just a factory) so you can inject fake dependencies into the object. These can then then just return canned responses and/or be checked that the class utilizes the dependencies how you intended.
As an example, if your code calls a repository to save, we don't really care in the business method test that the repository did actually save to a persistance store, only that it got called and returned some data if required. What you're really testing is how your code reacts to what the dependency returned, or if it was utilzed correctly - but not the dependency's actual functionality
Ideally the first test should have been representative of how the class/method will work and return data, so the test would still be valid once you're finished.