How to unit test old legacy application - java

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.

Related

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

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.

How to write unit tests for data access?

Unit tests have become increasingly important in modern software development, and I'm finding myself lost in the dust. Primarily a Java programmer, I understand the basics of unit tests: have methods in place that test fundamental operations in your application. I can implement this for the simple (and often used as examples) cases:
public boolean addNumbers(int a, intb) {return a + b;}
//Unit test for above
public boolean testAddNumbers() {return addNumbers(5, 10) == 15;}
What confuses me is how to move this out into practical application. After all, most simple functions are already in APIs or the JDK. A real world situation that I do frequently in my job is data access, i.e. writing DAOs to work with a database. I can't write static tests like the example above, because pulling a record set from an Oracle box can return a whole manner of things. Writing a generalized unit test that just looks for a particular pattern in the return set seems too broad and unhelpful. Instead, I write no unit tests. This is bad.
Another example of a case where I don't know how to approach writing tests is web applications. My web applications are typically built on a J2EE stack, but they don't involve much logic. Generally it's delivering information from databases with little to no manipulation. Are these inappropriate targets for unit tests?
In short, I've found the vast majority of unit test examples to focus on test cases that are too simplistic and not relevant to what I do. I'm looking for any (preferably Java) examples/tips on writing unit tests for applications that move and display data, not perform logic on it.
You generally don't write unit tests for DAOs, but integration tests. These tests basically consist in
setting the database in a well-known state, suitable for the test
call the DAO method
verify that the DAO returns the right data and/or changes the stateof the database as expected.
Shameless plug: DbSetup is good tool to do the first part. But other tools exist like DBUnit.
To test the business logic of the app (complex or not, that doesn't change much), you typically mock the DAOs using a mocking framework like Mockito:
SomeDao mockDao = mock(SomeDao.class);
when(mockDao.findAllEmployees()).thenReturn(Arrays.asList(e1, e2, e3));
SomeService service = new SomeService(mockDao);
someService.increaseSalaryOfAllEmployeees(1000);
// todo verify that e1, e2 and e3's salary is 1000 larger than before

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

Java unit testing - proper isolation?

I'd like to know if my approach to unit testing has been wrong:
My application has a boot strap process that initializes a several components and provides services to various sub-systems - let's call it the "controller".
In many cases, in order to unit test these sub-systems, I would need access to the controller as these sub-systems may depend on it. My approach to doing this unit test would be to initialize the system, and then provide the controller to any unit test that requires it. I achieve this via inheritance: I have a base unit test that initializes and tests the controller, then any unit test requiring the controller would extend this base class, and hence, have access to it.
My question is this:
(1) Is this achieving proper isolation? It makes sense to me that unit tests should be done in isolation so that they are repeatable and independent - is it ok that I am providing a real initialized controller rather than mocking it or attempting to mock the specific environment required by each test?
(2) As a best practice (assuming that my previous approach is OK) - should I be creating the controller over and over for each unit test, or would it suffice to create it once (its state is not changing).
If we are supplying a "real" controller to test another component, then strictly speaking we are performing an integration test rather than a unit test. This is not necessarily a bad thing, but consider the following points:
Cost of Creating the Controller
If the controller is a heavyweight object with a considerable cost to construct, then every unit test will incur this cost. As the number of unit tests grows in number, that cost may begin to dominate the overall test execution time. It is always desirable to keep the runtime of unit tests as small as possible to allow quick turnaround after code changes.
Controller Dependencies
If the controller is a complex object, it may have dependencies of its own that need to be instantiated in order to construct the controller itself. For example, it may need to access a database or configuration file of some kind. Now, not only does the controller need to be initialized, but also those components. As the application evolves over time, the controller may require more and more dependencies, just making this problem worse as time goes on.
Controller State
If the controller carries any state, the execution of a unit test may change that state. This, in turn, may change the behaviour of subsequent unit tests. Such changes may result in apparently non-deterministic behaviour of the unit tests, introducing the possibility of masking bugs. The cure for this problem is to create the controller anew for each test, which may be impractical if that creation is expensive (as noted above).
Combinatorial Problem
The number of combinations of possible inputs to the composite system of the unit under test and the controller object may be much larger than the number of combinations for the unit alone. That number might be too large to test practically. By testing the unit in isolation with a stub or mock object in place of the controller, it is easier to keep the number of combinations under control.
God Object
If the controller is conveniently accessible to all components in every unit test, there will be a great temptation to turn the controller into a God Object that knows everything about every component in the system. Even worse, those components may begin to interact with one another through that god object. The end result is that the separation between application components begins to erode and system starts to become monolithic.
Technical Debt
Even if the controller is stateless and cheap to instantiate today, that may change as the application evolves. If that day arrives after we have written a large number of unit tests, we might be faced with a large refactoring exercise of all of those tests. Furthermore, the actual system code might also need refactoring to replace all of the controller references with lighter weight interfaces. There is a risk that the refactoring cost is significant -- possibly even too high to contemplate, resulting in a system is "stuck" in an undesirable form.
Recommendation
In order to avoid these pitfalls now and in the future, my recommendation is to avoid supplying the real controller to the unit tests.
The full controller is likely to be difficult to stub or mock effectively. This will induce (desirable) pressure to express a component's dependencies as a "thin", focused interface in place of the "thick", "kitchen sink" interface that the controller is likely to present. Why is this desirable? It is desirable because this practice promotes better separation of concerns between system components, yielding architectural benefits far beyond the unit test code base.
For lots of good practical advice about how to achieve separation of concerns and generally write testable code, see Misko Hevery's guide and talks.
I think it's OK to provide a real controller. That will provide for a good integration test of your system. At my company we do a lot of what you're doing: a base test class that sets up the environment and the actual test cases that inherit it.
Hrm ... I think I might create it once. That'll test your controller also and make sure its state isn't changing and can bear repeated invocations.
If you're looking for a strict unit test, why not use mock objects, like EasyMock:
http://www.easymock.org/
That way you can provide "mock" behavior for the controller without ever instantiating it. Unitils also provides integration with EasyMock, such that if you extend the UnitilsJUnit4 unit test class, you get automatic mock object creation and injection. Unitils also provides for DB unit/integration testing, which might be overkill for your software, though.

Categories