Better to use #Autowired or new in Spring test class? - java

I was wondering about this question by having some trouble writting unit tests for my spring application.
Let's take the following example:
#SpringBootTest
#RunWith(SpringRunner.class)
public class AlbumDTOConverterTest {
#Autowired
private AlbumDTOConverter albumDTOConverter;
#Test
public void ToEntity_ReturnValue_NotNull() {
AlbumDTO albumDTO = new AlbumDTO("Summer album", new Date(), "This summer, we have made some wonderfull photos. Have a look!", null);
assertNotNull(albumDTOConverter.toEntity(albumDTO));
}
}
In order to make #Autowired work properly, I am launching a container with annotating the test class with #SpringBootTest.
The thing is that I think I am doing this wrong. In my opinion, I'll rather just create a new instance of AlbumDTOConverter by just using the new operator instead of using Spring's IoD.
What do you guys think about this ?

For unit tests you don't need a whole container to start. By definition, such units should be tested in isolation. Creating an instance of a class with the new keyword is perfectly fine. Even if the class has dependencies on other classes, you can also create them manually and pass to an appropriate constructor of the class.
Note that the unit is not the same as the class. The term of the unit is commonly confused among developers, especially beginners. You don't have to rely on the dependency injection in your unit tests. The container will only increase the time needed to execute the tests and the long execution time is the main reason why developers avoid running them very often. There is nothing wrong in manually building your dependency tree for a unit under tests.
In the long run, creating similar inputs for different tests might lead to duplication in the test code, but fortunately there are best practices for this problem, e.g. shared fixture.

If you are doing unit test then you should not use #Autowire every time.
Unit test basic says "Unit tests are responsible for testing a specific piece of code, just a small functionality (unit) of the code"
Now question is when to use spring capabilities ?
Sometimes, you'll need to do some unit tests relying on Spring framework like web service call, repository call etc. For example, if you have a repository that has a custom query using the #Query annotation, you might need to test your query. Also, if you are serialising/deserialising objects, you'd want to make sure that your object mapping is working. You might want to test your controllers as well, when you have some parameter validation or error handling. How can you be sure that you are using Spring correctly? In these situations you can take advantage of the new Spring Boot's test annotations.
I thinks this will give better idea.

Related

How do I replace frequently used new keyword with Spring calls 4 Unit testing?

Clarification:
The legacy code wasn't Sprung completely ( see what I did there ) and also test coverage is low. We are working to improve it now but we see uses of the new keyword everywhere and this is going to ruin our unit isolation. I'd rather not wire in a ref to the Spring Context as that ties us pretty closely to Spring and I can't use PowerMock due to an Architects directive. What we've been doing is putting all calls to new in protected methods so we can override but shouldn't Spring be doing that and how do we get Spring to do it? I can easily imagine creating an appropriately annotated method in a #Configuration annotated class with scope set to... hmmm.. nothing at all? That should mean that the class generates a new one on every call. Question is, how do I use that in my subject under test?

Why use Spring's Mock MVC when you have unit tets of your controller classes

I have seen people around me using Spring MVC in unit tests for controller classes, which is not helpful in what a unit test is for.
Unit tests are supposed to test your actual implementation of the controller class, and this can be achieved more accurately with simple Junit tests rather than using Spring Mock MVC.
But then the question arises, what's the real usage of Spring Mock MVC then? What do you need it for?
Let's say I have below code :
#Controller
#RequestMapping("/systemusers")
public class SystemUserController
{
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String getUser(final Model model)
{
// some logic to return user's details as json
return UserDetailsPage;
}
}
I can test this class/controller more accurately with Junit than with Spring Mock MVC (all it does is generates some json which can be asserted with junit).
I can also test with Spring Mock MVC like using the correct endpoint returns the correct HTTP status and correct response page string.
But doesn't that mean that we are testing Spring MVC's functionality rather than the actual code for method under test?
P.S. : I have kept the code to minimal which I think is sufficient to explain my question. Assume there is no compilation error.
When it comes to the unit-testing of a Controller (or any Endpoint which is exposed) classes, there are two things that we will validate:
(1) Controller's actual logic itself as standalone i.e., right service calls are invoked or not etc..
(2) Request URL mapping and the Response status & object
Item (1) above is what we test in general with all other classes like Services, Utility classes etc..
Item (2) needs to be covered/tested additionally for the endpoints (controller classes) which have been exposed, so whether we use Spring's MockMVC or other machinery to do that, it is up to us really.
Spring's MockMVC indeed helps us to start the in-memory servlet container & check that the right controller methods are invoked & then the right responses have been coming out.
From my personal experience, testing the controllers (for item(2)) helped me to resolve URL mapping conflict issues (of course, within the same controller) etc.. straight away rather than fixing them at the later stages of the project.
Based on My experience I will try to answer your question.
First thing we need to understand why we use unit testing?
It is a extra check used by developer to write clean working code.
Clean working code means every line written should be doing what it is
expected to do. how do you achieve this? Here comes unit testing. The
standalone unit of code you are writing should be verified standalone.
Method is best part in code which represents standalone unit code
template.
Unit Testing for Method
Developer should write a test for method which describes the method
behavior. And possible checks that i follow is is it returning the
expected value considering all positive scenarios? is it working in
case of Exception? is it calling correct subsequent methods ?
Developer should verify the method by actually calling it providing a
mock environment
Below is possible answer to your question. though it is solely based upon the developers.
Controller methods are intended to invoke correct service call accepting input and returning the value from service to view.
So I may think of write a unit test case for controller method as you are thinking is a right approach. But you should verify the method by calling it in same way as it will be called in real time.
so you need to call controller method in same way as MVC does. Hence it is better option to use MockMVC.
MockMVC is also useful to verify the urls, input params , response and status which are part of controller method. Considering these all it makes it standalone unit of code.
Hope this will clarify your doubt.

How to unit test old legacy application

I was assigned to old web applicaton(JSF 1.2 + Eclipselink), there is no middleware like EJB or Spring and service layer of application is composed of POJO that directly calls EntityManager. Structure of the code is like this SomeBean(backing bean) -> SomeServices(here is mix of business logic and data access code), no seperate DAO layer. The code on service classes usually looks like this(here very simplified):
public void someMethod(SomeEntity someEntity, ....) throws SomeServiceExeption {
try{
entitiyManager.getTransaction.begin();
//lotOfLogicHereAndCallingSomeOtherPrivateMethods
entitiyManager.getTransaction.commit();
}catch(Exception e){
log.error("");
if(entitiyManager.getTransaction..isActive()){
entitiyManager.getTransaction.rollback();
}
throw new SomeServiceExeption(e);
}
}
This application has only few tests, that were testing almost nothing, so I am trying to cover as much code as possible with unit tests(there will be some changes commintg into application that will require a lot of changes in legacy code which is not covered by tests). My question is how would you unit test code like this. I have three ideas:
Refactor to tests. I could introduce DAO layer and put all
entityManager calls there. But refactoring without tests is allways
problem.
Mock EntityManager. I tried this several times with EasyMock, it works
and helps me to at least have some code coverage of code that
requires changes, but is probably not good style, as you should not
mock api that does not belong to you. Also to prepare EntityManager mocks requires a lot of time and code
Instead of unit testing, do integration testing with hsqldb or h2
and some dummy test data. Well this would require probably most of
the work and tests would be slow. Also I want to cover mostly
bussiness logic, not data access.
I would probably first add some integration tests and get coverage on the parts you want to refactor. Then, you can go on refactoring to more isolated units that are individually testable. If refactored correctly, you can then unit test your business logic seperately from the storage.
It's always a good idea to have some integration tests, so that would be a good place to start.
In any case, I wouldn't refactor code that's not covered by any tests.

Should I unit test generated Java code?

Simple question. If I use spring-data to generate CRUD methods for my DAO layer, should I still write unit tests against the generated methods? Or would that be the equivalent of unit testing library code?
Thanks in advance.
EDIT: To clarify, I'm asking whether or not the unit test needs to be written in addition to a suite of integration tests that get run before a release. For example, a unit test for the findAll() method of the DAO layer would be similar to the following:
class DepartmentDAOTest extends spock.lang.Specification {
/* ... */
def "returns all departments"() {
setup:
def result = new List<Department>()
when:
result = dao.findAll()
then:
result.size() == EXPECTED_SIZE
}
}
Whereas an integration test would be run probably by a test team or developer by hand, possibly before tagging a new release. This could either be automated using JWebUnit or Geb, and tests every component (including the platform) to ensure they work as expected when "integrated."
If I were to write the DAO implementation by hand using JdbcTemplate there would be no question that I should unit test every method. When I unit test the service layer (which makes calls to the DAO layer) I can mock out the DAO layer so I don't test it twice.
If I make a call into a third-party library like pdfbox for generating a PDF, there's an expectation for each method to work (because it is tested as a part of the pdfbox project). I don't test that their drawSquare method really draws a square, but during integration testing I'll see that my export PDF functionality correctly exports a PDF the way we want it to.
So the question should really be re-worded as, "Under which testing phase should I test my usage of spring-data?"
First, there is no code generated at all. We built a query meta model from the query methods you declare and dynamically execute these queries. The short answer here is: you definitely should test these methods declared. The reason is as obvious as it is simple: the query method declarations - no matter if they use derived queries or manually declared ones - interact with the mapping metadata you defined for your entities. Thus, it's definitely reasonable to check the query method execution to make sure you see the expected results. This then of course an more of an integration test and a semantical check for the queries executed, rather than a classical unit test.
No. As a general rule, don't test the platform.

What is the best approach for Unit testing when you have interfaces with both dummy & real implementations?

I'm familiar with the basic principles of TDD, being :
Write tests, these will fail because of no implementation
Write basic implementation to make tests pass
Refactor code
However, I'm a little confused as to where interfaces and implementation fit. I'm creating a Spring web application in my spare time, and rather than going in guns blazing, I'd like to understand how I can test interfaces/implementations a little better, take this simple example code I've created here :
public class RunMe
{
public static void main(String[] args)
{
// Using a dummy service now, but would have a real implementation later (fetch from DB etc.)
UserService userService = new DummyUserService();
System.out.println(userService.getUserById(1));
}
}
interface UserService
{
public String getUserById(Integer id);
}
class DummyUserService implements UserService
{
#Override
public String getUserById(Integer id)
{
return "James";
}
}
I've created the UserService interface, ultimately there will be a real implementation of this that will query a database, however in order to get the application off the ground I've substituted a DummyUserService implementation that will just return some static data for now.
Question : How can I implement a testing strategy for the above?
I could create a test class called DummyUserServiceTest and test that when I call getUserById() it'll return James, seems pretty simple if not a waste of time(?).
Subsequently, I could also create a test class RealUserService that would test that getUserById() returns a users name from the database. This is the part that confuses me slightly, in doing so, does this not essentially overstep the boundary of a unit test and become more of an intergration test (with the hit on the DB)?
Question (improved, a little): When using interfaces with dummy/stubbed, and real implementations, which parts should be unit tested, and which parts can safely be left untested?
I spent a few hours Googling on this topic last night, and mostly found either tutorials on what TDD is, or examples of how to use JUnit, but nothing in the realms of advising what should actually be tested. It is entirely possible though, that I didn't search hard enough or wasn't looking for the right thing...
Don't test the dummy implementations: they won't be used in production. It makes no real sense to test them.
If the real UserService implementation does nothing else than go to a database and get the user name by its ID, then the test should test that it does that and does it correctly. Call it an integration test if you want, but it's nevertheless a test that should be written and automated.
The usual strategy is to populate the database with minimal test data in the #Before annotated method of the test, and have you test method check that for an ID which exists in the database, the corresponding user name is returned.
I would recommend you to read this book first: Growing Object-Oriented Software Guided by Tests by Steve Freemand and Nat Pryce. It answers your question and many others, related to TDD.
In your particular case you should make your RealUserService configurable with a DB-adapter, which will make real DB queries. The service itself will the servicing, not data persistence. Read the book, it will help a lot :)
JB's Answer is a good one, I thought I'd throw out another technique I've used.
When developing the original test, don't bother stubbing out the UserService in the first place. In fact, go ahead and write the real thing. Proceed by following Kent Beck's 3 rules.
1) Make it work.
2) Make it right.
3) Make it fast.
Your code will have tests that then verify the find by id works. As JB stated, your tests will be considered Integration Tests at this point. Once they are passing we have successfully achieved step 1. Now, look at the design. Is it right? Tweak any design smells and check step 2 off your list.
For step 3, we need to make this test fast. We all know that integration tests are slow and error prone with all of the transaction management and database setups. Once we know the code works, I typically don't bother with the integration tests. It is at this time where you can introduce your dummy service, effectively turning your Integration Test into a unit test. Now that it doesn't touch the database in any way, we can check step 3 off the list because this test is now fast.
So, what are the problems with this approach? Well, many will say that I still need a test for the database-backed UserService. I typically don't keep integration tests laying around in my project. My opinion is that these types of tests are slow, brittle, and don't catch enough logic errors in most projects to pay for themselves.
Hope that helps!
Brandon

Categories