Is using a test entity manager a legitamate testing practice? - java

I'm told by Devs senior to me, but less experienced with Hibernate, that wiring an entity manager into your Unit Test suite to be used to set up your database is not a legitimate practice. ...but I'm sceptical because I've already worked at several places where this was done. Note that Hibernate is already being used to set up the test H2 db.
I've been asked to "prove" that it is legitimate. How can I do this? Is this a community standard way of doing it? Does anyone know of a good link I can use? Although I am myself on the hunt for such, I smell a bit of religion here so I'm probably going to need a really killer one or perhaps a large number of them.

What your senior devs are referring to is, proper, white-box testing.
When you are doing Unit testing, you want to test only the given unit. This becomes more complicated when you start involving things like a database, or some external web service. The point remains, however: you still only want to test the one piece of code the Unit test is intended for; not some database.
Whether or not you have confidence in hibernate, or your database, is irrelevant. You need to "mock" the database transaction, the EntityManager, etc. I would look into something along the lines of EasyMock. Really its all up to you what you want to use. If you google for "mock junit" you will likely come up with a list of results where you can choose the framework that is right for you. The right framework for you, is a little beyond the scope of this discussion though.
Once you find what you want to use, the idea is that inside of your Unit test, instead of getting a real EntityManager, you have a mock object which you have mocked in such a way that:
the documentation says that A will happen if I invoke method C, so I told the mock framework about it so it can fake it for me, so I don't have to rely on things outside of my Unit test
The reason why you want to mock an object like that, is because you can't rely on any other code that is not within that one Unit to work properly. Despite what you expect, and despite what the documentation says you should expect, if the code is written poorly, or in your case, if the database fails for some reason, then the unit test will fail. You can see how this might be a problem, because your function may execute flawlessly, but it fails because the database failed. This is not how unit testing is supposed to work - that's why its called unit testing...to test only a single unit at a time.
ALWAYS mock complicated Objects or functionality. Leaving things like String#equals(java.lang.Object) is OK. With doing this, you want to find a good middle ground. If you mock too much of your Unit test, then you lose confidence in the Unit test because your unit test is not actually invoking any actual code of yours. If you don't mock enough, then you are not doing unit testing properly, and your unit test is relying on things that have nothing to do with your code (i.e. database failure, third-party code written poorly, etc).
Your senior devs are correct. If you are using the real EntityManager in your Unit tests, then you are not actually doing unit testing at all.

Related

How to start writing Unit Tests for SpringBoot(The proper way)?

I'm new to the world of unit testing in Spring and with some research I think I'll be using Junit5 with mockito and AssertJ library for the same. I am just starting out and it does look really confusing.
1st Question: Do we write our units first?? meaning our controller methods or service methods or any unit.. Do we write those firsts and then write tests for them or Do we first design our tests thinking ok, this methods needs to do this so I'll be writing my tests and then actually implement what I have to implement? I know this a bit silly of a question but I want to know how people go about it this in their work.
2nd Question: Suppose we write our tests, it fails for a certain unit. After it fails, what should be my first approach i.e. should I be thinking that the way I wrote the test was bad, so I need to properly write the test in order for the test to pass, or should I be like, ok my unit must have been bad, I'll change or refactor my code right away and then again test it after the refactoring? What is the 'thing' to do just after your test fails for some unit?
3rd Question/Help: Testing simple CRUD methods seems okayish and there are a lot of resources for it although it's still confusing.. Could someone recommend me a github repo or a link or any source where unit tests have been written for some complex functions with some actual logic inside it and not only CRUD operations? I want to see how tests are written for the logic inside the code and how things are actually tested.
Any help would be highly valued. Thank-you, Have a good day.
You are asking if you should to "Test Driven Development" (TDD for short) , where writing test first is the basic idea. But since you did not write any tests yet, start small, write the test afterwards, and as soon you feel comfortable writing tests, write all test before implementing. And read more about "TDD", google is you friend.
this depends if you trust the test code more than the production code or vice versa. Of cause, test code can also be buggy. But test code should actually be easier to understand, so it should be easier to decide who much you can trust it.
See https://medium.com/#sheikarbaz5/spring-boot-with-tdd-test-driven-development-part-i-be1b90da51e or https://livebook.manning.com/book/spring-boot-in-action/chapter-4/

The cost of setting up tests in JUnit - using mocked objects versus repository-tests in legacy code

I work on a project which has existed for many years. The time it takes to build the project with all tests is almost sensational (not in a good way). This is mainly due to a lot of modules, as well as heaps of unit tests which uses a repository to set up test data rather then to mock the desired behaviour. Unit tests using a repository use a lot of time for test setup, and they run quite slowly. This adds up to a lot of time as the system is quite large.
We write all new unit tests by using Mockito to mock the repository (except when we are actually testing the repository obviously). We also try to rewrite all existing unit tests to using mocks of the repository instead of an actual repository whenever we have the time and opportunity. Completely eliminating the use of repo's in our tests has a huge effect on how much time it takes to run the tests.
A lot of the legacy code sets up its test data by using builders and test-utilities which in turn uses the repository. As the domain is quite complex, this often involves setting up a fair amount of objects and how they are related to each other. Re-writing a class of tests (say ~15 tests) to using only mocked object can therefore be quite time-consuming. And as everywhere else, time is not an infinite resource.
If we are adding some new functionality to a class, it would be far easier to just write one new repository test (in addition to the existing 15) than to find out exactly how the test data needs to be set up by using different mock objects.
I have tried to find some information on how and to what extent the test setup affects the actual time it takes to run the tests, but I have failed to find any useful information. My only "facts" are the observations I make when running a test class. The test setup for a repo test may easily take ~10 seconds, while the test setup for a mocked test class starts in less than a second.
NOTE: I am aware that I can use JUnit Stopwatch to benchmark a single or a set of tests, but my question is more concerned with best practices than exactly how long it takes me to run my tests.
I have two questions:
Say I encounter a test class which already has 15 unit tests where none of them mocks any behaviour. I write a test and do a small fix in the class. I do not have the time to re-write the whole test class to mock objects. Should I just add a new test without mocking any behaviour and follow the existing (and bad) pattern? Does it really matter whether I have 15 non-mocked tests and 1 mocked test or if I have 16 non-mocked tests?
In my test class with 15 unit tests, some of the tests are easier to refactor than others. Is it worth it to re-write only five of the tests to using mocked objects? Is it against best practice or in any other way not good to have a test class where some of the tests uses mocks and some don't?
Your question is really subjective but I'll try to suggest few options you can explore. It all depends upon how much you're willing to spend.
Should I just add a new test without mocking any behavior and follow the existing (and bad) pattern? Does it really matter whether I have 15 non-mocked tests and 1 mocked test or if I have 16 non-mocked tests?
Its not about just one new test. If you're still writing in bad/slow pattern, you're just increasing technical debt. You've to lay out the best practices for writing new unit tests yourself.
In my test class with 15 unit tests, some of the tests are easier to
refactor than others. Is it worth it to re-write only five of the
tests to using mocked objects?
Absolutely. Why not? You saying for yourself the improvements you're getting by following newer style of code.
Is it against best practice or in any other way not good to have a
test class where some of the tests uses mocks and some don't?
Well one best practice is to have consistent code everywhere. Mix of old styled repositories and newer one with mocks does not go too well as far as best practices are concerned. But I'd be more concerned if the code you write is not well covered with unit tests, whatever style if may be.
At the end of the day, you're the one to decide and look at all the trade offs like how much build time improvements can you achieve by newer mocked repositories, what is the frequency of your builds, and can this be achieved using hardware improvements and other factors.
As written by #ShanuGupta there is not general answer to your question.
But here is my thought:
After correctness the readability is the second most desirable value of code, especially test code (since it is executable specification)
On the other hand there is no rule that a unit cannot have more than one Test class. Therefore I'd separate "old" test methods not using mocks from the "mocking" tests by placing them in separate test classes.

Unit testing a service, which works as a mediator between two other services

I have a service, which works as a mediator between two other services. It basically validates the inputs, then passes them to those two service sequentially (by trying to keep transactional integrity), and then, if everything goes well, saves a result to the database.
My problem now is to test this service in isolation. Of course, I can provide stubs to satisfy the dependencies. I can also test the validation of inputs, whether appropriate data is saved in the DB in a normal case, as well as whether transactional integrity is kept if any of the dependencies throws an exception.
Yet, this is only half of what the service really does. My dilemma is if I should try to prove whether the other two dependency services actually processed the data appropriately as well? The scope of my service is quite broad, so I guess it is better to also know if the dependency services also did their job well. Yet, this gets out of the scope unit testing, and moves into integration testing, right?
I am kind of confused here.
If you're asking about unit-testing, then the way to do it is to test the class in isolation using mocks or stubs.
BUT, if you feel that just doing that is not enough, you can write some component tests, where you use the all the real classes you want to test, and use a stub (or inmemory) database and mock some of the dependencies that you consider not important for what you are trying to test.
In the past, I've tested small clusters of classes that had a high interaction between them in this way (and sometimes skipping unit-tests for those classes, as the component tests covered all the scenarios). Obviously, the problem with doing this is that the number of scenarios grows almost exponentially the more classes you're testing. Maybe you can test the bridge and the 2 real classes that use that bridge.
You should do both.
For unit testing, definitely use mock-objects for dependencies, preferrably using a tool like EasyMock. As a sidenote, if you feel that the functionality of your mediator service is too broad for unit testing, you may want to consider breaking it down into smaller pieces.
Of course, you additionally should do integration testing as well, using real dependencies, to make sure your services work together as intended.

Struts2 action - test it or not?

I'm currently working on one project, that uses Struts2 framework. We use separate component for DB accessing, which is well tested. At the same time, project, that we work on has a lot of Actions, that are not tested. In most of the actions we use at least one DB-service call. So on one hand these actions are pretty simple. I'm not sure - should unit tests be written for that or not?
I think that good practice is write unit tests always, but these actions are so simple and I'm under big pressure from management side right now. So, is it critical or not - to leave Struts2 actions without unit tests?
Here are the three main reasons for writing unit tests.
It helps you know that your code works now.
It helps defend your code against regression errors, when functionality is added or changed in the future.
If you write unit tests before you write your code, it focuses your design process in a really good way - read up on TDD to learn more about the benefits of doing this.
So ask yourself whether any of these three reasons for writing unit tests apply here. If the answer is "no" for all three questions, then consider the cost of writing the unit tests, and of keeping them in your code base. Compare this cost with the possible benefit. Make an intelligent decision about whether you should be writing unit tests, and be prepared to defend that decision to your manager.
But don't carry a preconceived notion that "unit tests are always good, for every class". And don't carry the opposite notion - that "unit tests are always unnecessary". Neither is true.
I'm in the same camp as Dhanji Prasanna who worked on Guice and Google Wave. Its not about 100% coverage, its about writing valuable tests that provide the right feedback for the right components in a way that aids development and protects against code regression.
For one of my Struts2 apps, we had very very complex data validation requirements. Thousands. We used the struts2-junit-plugin to test the action classes within their integrated context with Spring 3 IoC and Struts2 validation and a custom mechanism for populating mock requests with lots of different data scenarios. These tests were/are invaluable both during development and as a maintenance tool.
But for some of our simpler actions, I don't see much value coming back compared to the time spent to write them. But then, they don't take too long to write if they are very simple, either.
I have also seen cases where the 100% coverage notion led to 100% of classes having thoughtless, worthless tests being written for them. For my money, I vote for identifying the areas where the tests will provide the most value up front and focusing on doing those very well.
Must write Unit Test for functions could be problematic, but in anyway maybe in a future will be validations in the Actions that would be good can test that.
The time spend for test the actions must be a little bit and I would recommend do it, every tier in your app must have some functionally if not is a unnecessary and must review the architecture.

How can I improve my junit tests

Right my junit tests look like a long story:
I create 4 users
I delete 1 user
I try to login with the deleted user and make sure it fails
I login with one of the 3 remaining user and verify I can login
I send a message from one user to the other and verify that it appears in the outbox of the sender and in the inbox of the receiver.
I delete the message
...
...
Advantages:
The tests are quite effective (are very good at detecting bugs) and are very stable, becuase they only use the API, if I refactor the code then the tests are refactored too. As I don't use "dirty tricks" such as saving and reloading the db in a given state, my tests are oblivious to schema changes and implementation changes.
Disadvantages:
The tests are getting difficult to maintain, any change in a test affects other tests. The tests run 8-9 min which is great for continuous integration but is a bit frustrating for developers. Tests cannot be run isolated, the best you can do is to stop after the test you are interested in has run - but you absolutely must run all the tests that come before.
How would you go about improving my tests?
First, understand the tests you have are integration tests (probably access external systems and hit a wide range of classes). Unit tests should be a lot more specific, which is a challenge on an already built system. The main issue achieving that is usually the way the code is structured:
i.e. class tightly coupled to external systems (or to other classes that are). To be able to do so you need to build the classes in such a way that you can actually avoid hitting external systems during the unit tests.
Update 1: Read the following, and consider that the resulting design will allow you to actually test the encryption logic without hitting files/databases - http://www.lostechies.com/blogs/gabrielschenker/archive/2009/01/30/the-dependency-inversion-principle.aspx (not in java, but ilustrates the issue very well) ... also note that you can do a really focused integration tests for the readers/writers, instead of having to test it all together.
I suggest:
Gradually include real unit tests on your system. You can do this when doing changes and developing new features, refactoring appropriately.
When doing the previous, include focused integration tests where appropriate. Make sure you are able to run the unit tests separated from the integration tests.
Consider your tests are close to testing the system as a whole, thus are different from automated acceptance tests only in that they operate on the border of the API. Given this think about factors related to the importance of the API for the product (like if it will be used externally), and whether you have good coverage with automated acceptance tests. This can help you understand what is the value of having these on your system, and also why they naturally take so long. Take a decision on whether you will be testing the system as a whole on the interface level, or both the interface+api level.
Update 2: Based on other answers, I want to clear something regarding doing TDD. Lets say you have to check whether some given logic sends an email, logs the info on a file, saves data on the database, and calls a web service (not all at once I know, but you start adding tests for each of those). On each test you don't want to hit the external systems, what you really want to test is if the logic will make the calls to those systems that you are expecting it to do. So when you write a test that checks that an email is sent when you create an user, what you test is if the logic calls the dependency that does that. Notice that you can write these tests and the related logic, without actually having to implement the code that sends the email (and then having to access the external system to know what was sent ...). This will help you focus on the task at hand and help you get a decoupled system. It will also make it simple to test what is being sent to those systems.
unit tests should - ideally - be independent, and able to run in any order. So, I would suggest that you:
break up your tests to be independent
consider using an in-memory database as the backend for your tests
consider wrapping each test or suite in a transaction that is rolled back at the end
profile the unit tests to see where the time is going, and concentrate on that
if it takes 8 minutes to create a few users and send a few messages, the performance problem may not be in the tests, rather this may be a symptom of performance problems with the system itself - only your profiler knows for sure!
[caveat: i do NOT consider these kinds of tests to be 'integration tests', though i may be in the minority; i consider these kinds of tests to be unit tests of features, a la TDD]
Now you are testing many things in one method (a violation of One Assertion Per Test). This is a bad thing, because when any of those things changes, the whole test fails. This leads it to not being immediately obvious why a test failed and what needs to be fixed. Also when you intentionally change the behaviour of the system, you need to change more tests to correspond the changed behaviour (i.e. the tests are fragile).
To know what kind of tests are good, it helps to read more on BDD: http://dannorth.net/introducing-bdd http://techblog.daveastels.com/2005/07/05/a-new-look-at-test-driven-development/ http://jonkruger.com/blog/2008/07/25/why-behavior-driven-development-is-good/
To improve the test that you mentioned, I would split it into the following three test classes with these context and test method names:
Creating user accounts
Before a user is created
the user does not exist
When a user is created
the user exists
When a user is deleted
the user does not exist anymore
Logging in
When a user exists
the user can login with the right password
the user can not login with a wrong password
When a user does not exist
the user can not login
Sending messages
When a user sends a message
the message appears in the sender's outbox
the message appears in the reciever's inbox
the message does not appear in any other message boxes
When a message is deleted
the message does not anymore exist
You also need to improve the speed of the tests. You should have a unit test suite with good coverage, which can run in a couple of seconds. If it takes longer than 10-20 seconds to run the tests, then you will hesitate to run them after every change, and you lose some of quick feedback that running the tests gives you. (If it talks to the database, it's not a unit test, but a system or integration test, which have their uses, but are not fast enough to be executed continually.) You need to break the dependencies of the classes under test by mocking or stubbing them. Also from your description it appears that your tests are not isolated, but instead the tests depend on the side-effects caused by previous tests - this is a no-no. Good tests are FIRST.
Reduce dependencies between tests. This can be done by using Mocks. Martin Fowler speaks about it in Mocks aren't stubs, especially why mocking reduces dependencies between tests.
You can use JExample, an extension of JUnit that allows test methods to have return values that are reused by other tests. JExample tests run with the normal JUnit plugin in Eclipse, and also work side by side with normal JUnit tests. Thus migration should be no problem. JExample is used as follows
#RunWith(JExample.class)
public class MyTest {
#Test
public Object a() {
return new Object();
}
#Test
#Given("#a")
public Object b(Object object) {
// do something with object
return object;
}
#Test
#Given("#b")
public void c(Object object) {
// do some more things with object
}
}
Disclaimer, I am among the JExample developers.
If you use TestNG you can annotate tests in a variety of ways. For example, you can annotate your tests above as long-running. Then you can configure your automated-build/continuous integration server to run these, but the standard "interactive" developer build would not (unless they explicitly choose to).
This approach depends on developers checking into your continuous build on a regular basis, so that the tests do get run!
Some tests will inevitably take a long time to run. The comments in this thread re. performance are all valid. However if your tests do take a long time, the pragmatic solution is to run them but not let their time-consuming nature impact the developers to the point that they avoid running them.
Note: you can do something similar with JUnit by (say) naming tests in different fashions and getting your continuous build to run a particular subset of test classes.
By testing stories like you describe, you have very brittle tests. If only one tiny bit of functionality is changing, your whole test might be messed up. Then you will likely to change all tests, which are affected by that change.
In fact the tests you are describing are more like functional tests or component tests than unit tests. So you are using a unit testing framework (junit) for non-unit tests. In my point of view there is nothing wrong to use a unit testing framework to do non-unit tests, if (and only if) you are aware of it.
So there are following options:
Choose another testing framework which supports a "story telling"-style of testing much better, like other user already have suggested. You have to evaluate and find a suitable testing framework.
Make your tests more “unit test”-like. Therefore you will need to break up your tests and maybe change your current production code. Why? Because unit testing aims on testing small units of code (unit testing purists suggest only one class at once). By doing this your unit tests become more independent. If you change the behavior of one class, you just need to change a relatively small amount of unit test code. This makes your unit test more robust. During that process you might see that your current code does not support unit testing very well -- mostly because of dependencies between classes. This is the reason that you will also need to modify your production code.
If you are in a project and running out of time, both options might not help you any further. Then you will have to live with those tests, but you can try to ease your pain:
Remove code duplication in your tests: Like in production code eliminate code duplication and put the code into helper methods or helper classes. If something changes, you might only need to change the helper method or class. This way you will converge to the next suggestion.
Add another layer of indirection to your tests: Produce helper methods and helper classes which operate on a higher level of abstraction. They should act as API for your tests. These helpers are calling you production code. Your story tests should only call those helpers. If something changes, you need to change only one place in your API and don't need to touch all your tests.
Example signatures for your API:
createUserAndDelete(string[] usersForCreation, string[] userForDeletion);
logonWithUser(string user);
sendAndCheckMessageBoxes(string fromUser, string toUser);
For general unit testing I suggest to have a look into XUnit Test Patterns from Gerard Meszaros.
For breaking dependencies in your production tests have a look into Working Effectively with Legacy Code from Michael Feathers
In addition to the above, pick up a good book on TDD (I can recommend "TDD and Acceptance TDD for Java Developers"). Even though it will approach from a TDD point of view there is alot of helpful information about writing the right kind of unit tests.
Find someone who has alot of knowledge in the area and use them to figure out how you can improve your tests.
Join a mailing list to ask questions and just read the traffic coming through. The JUnit list at yahoo (something like groups.yahoo.com/junit). Some of the movers and shakers in the JUnit world are on that list and actively participate.
Get a list of the golden rules of unit tests and stick them on your (and others) cubicle wall, something like:
Thou shalt never access an external system
Thou shalt only test the code under test
Thou shalt only test one thing at once
etc.
Since everyone else is talking about structure I'll pick different points. This sounds like a good opportunity to profile the code to find bottleknecks and to run it through code coverage to see if you are missing anything (given the time it takes to run it the results could be interesting).
I personally use the Netbeans profiler, but there are ones in other IDEs and stand alone ones as well.
For code coverage I use Cobertura, but EMMA works too (EMMA had an annoyance that Cobertura didn't have... I forget what it was and it may not be an issue anymore). Those two are free, there are paid ones as well that are nice.

Categories