I try to write an big test class.
I'm using Junit, Hibernate and TopLink and H2 database. Before this I used EJB3Unit (including Hibernate and H2).
My test class has 57 test methods. If I run all test at once randomized one or more test fails. If I run each test alone, I get no error.
Has anyone an idea what's going wrong? And how I can prevent this?
For each test method I create a new in memory database with a different name.
I create a new entitymanagarfactory and entitymanagar instance.
I've disabled second level caching.
I create all table via script (no error occurs so database is really fresh).
I do some db actions and test.
I clear session and em.
I drop all object in my in-memory database
I shut down the database
I close em and emf.
Have I to do more?
Thanks a lot...
It seems that there is dependency among the tests.
ideally you should restore the database to its original state after each test by using a tearDown method (in JUnit 4, use the #After annotation).
If you're already doing that then the dependency is more subtle. To find out its cause I suggest you start doing a binary search on the tests: comment out half of your tests. If the random failure persists then comment out half of the remaining half (and so on). If the failure disappears then the problem is in the other half: uncomment and comment out the other half. This process will converge quite quickly.
Good hunting.
Dependencies are a possibility for this random failing.
An other reason can be the order of elements in a collection. Once i was writing a test and depended on the first element. It was not sorted so i was not sure that the object i was asking was always the same.
Related
I have DAO using Spring's jdbcTemplate with Create Read Update (no Delete) operation.
Create method have ID parameter which is unique key in table.
Except mocking DAO, how can I actually test create without getting constraint violation?
Using random ID still can fail sometimes
Should I override setAutoCommit to avoid adding record? is it still consider a valid unit test?
Must I delete in SQL the record in database beforehand or is there spring option for this types of tests?
Or should I consider it as integration test and not unit test?
EDIT
I'm using Oracle, I can't use sequence for creating values for the ID
We have a few Data sources exists (not for testing) in production
It really depends on what is the purpose of such a test, not all the tests are "unit tests" with this respect.
If, for example, the goal is to test the "service" that encapsulates a business logic, but from this service, sometimes there are calls to DAO, then probably the best way is to just mock the DAO as you suggest.
In this case, DAO obviously won't be covered by this test, but the service will.
If the purpose is to test SQL statements (and I assume that DAO contains nothing but SQL statements + maybe transforming them into the domain object), then mocking is not an option.
In this case, the test should include calls to some kind of database, but in this case, it's not called a unit test anymore (a unit test is something that runs really fast and only in memory, no DBs, no I/O, etc.) I'll call this an integration test (as you also suggest), but different people have probably different names for this kind of tests.
In practice, we need both kinds of tests because they test different things
So, how to test this?
First of all the decision should be made, which database should be used, there are 3 approaches here:
Run with a real database, shared between the users, tests assume its pre-installed
Run with an in-memory database
Run the DB docker image of the DB when the test suite runs, and destroy it afterwards
While the discussion of which approach is better is very interesting on its own, its out of scope for this question IMO, each choise has its implications.
Once you're done with this decision, you should decide how to work with this database from the code.
Usually spring tests use the following pattern:
open a transaction before the test
run the test (change the data, even change the schema - add columns, tables if you want). Do assertions
Regardless the tests result, rollback the transaction so that the data will be just like before the test
So if you follow this approach for all your tests, they'll start with "empty" data state so that no constraint violations are expected
This effectively solves also the "deletion of the record" question because the data will be deleted anyway when the transactions is rolled back.
Now regarding the Deletion of the record outside a transaction.
An obvious approach is to execute an sql of deletion right from the test (outside the DAO), so that DAO (a production code won't be changed)
You can inject DataSource/JDBCTemplate right into the test (Spring test perfectly supports this) and call the required SQL from there
I have a bug that manifest himself only when database is slow. It applies to even simplest database operations (select, etc).
I would like to create test, where I force my database to be slow. How to do that?
I use Spring Boot, Spring Data, Hibernate, MariaDB.
Ideally, I want the 'slow database' part to be completely contained in the test code, in my java application. That way, test will be completely automated and self-contained.
I want to slow down database access only for one test (not globally, for all access).
I was proposed to introduce database trigger (BEFORE SELECT) with sleep
But this is not flexible, because it slows down every access, not access just for one test.
I see four possible solutions for this problem.
You don't have to create slow database, you can create slow connection to the database. If you run database on a different (Virtual) machine, there are systems that help simulating shitty internet connections by delaying network responses randomly.
You can use sleep(10) function that is provided by your database, this would require "injecting" it into SQL query or override method for the purpose of test and replace SELECT with SELECT SLEEP(10).
Simulate stress-test on the database with mysqlslap if you use mysql.
Another solution, a bit stupid tho, you can use spring-aop and attach a delay aspect before and after the DAO method execution with random small sleep. This way you have control over it, don't have to modify existing code and let spring make the job of doing the delay without integration into real-system. Not that stupid after all. This one is quite flexible and I think I would go with it. Easiest to setup.
If it's stupid, but it works, it's not stupid.
I had a similar need when developing on a SQL Server DB.
To simulate a slow query you can use (but this is specific to SQL Server):
select * from TABLE
WAITFOR DELAY '00:00:45'--to simulate 45 seconds of delay
If you want to write a Spring Boot Test, maybe you can use the #SpyBean annotation
#SpyBean
SomeBeanCallingTheDatabase someBeanCallingTheDatabase;
//...
// in the test method
doAnswer(answer-> {
Thread.sleep(300L); //any value here
return answer.callRealMethod();
})
.when(someBeanCallingTheDatabase)
.find(any());
// call the service using the bean above
The easy answer is to write a test repository class that has a Thread.sleep embedded in it.
credit: this answer was provided by https://stackoverflow.com/users/37213/duffymo in the comment.
Here's the scanario:
I am working on a DAO object which uses hibernate criteria API to form a number of complicated queries to perform certain tasks on the database (keyword search across multiple fields for example).
We need to unit test this to ensure that the generated query is correct for various scenarios. One way of testing it -which could be preferable- would be to test the hibernate criteria is created correctly by checking it at the end and mocking the database interaction. However this is not desirable as firstly it's kinda cheating (it's merely duplicating what the code would be doing) and also it doesn't check if the criteria itself causes hibernate to barf or when it goes to database it causes issues.
The option to use is then run the query against a test database. However, for historical reasons there is no static test database (one that code be checked in as part of the code for example) and the remit of my project does not allow me to embark on creating one, we have to content with testing against a shared development database that's periodically refreshed with production data.
When theses refreshes happen, the data behind the tests could change too, and this would make our unit tests brittle. We can get over it by not using exact numbers in tests but it's not really adequate testing that way.
The question is then: what do people do in cases like this to make tests less brittle? One option that I have in mind is to run a native SQL that does the same query (behaviourally - it doesn't have to be exact same as the query generated by hibernate) to get the expected number and then run the DAO version to see if it matches. This way, the behaviour of the query can be always implemented in the initial native SQL and you will always have the correct numbers.
Any feedback on this or other ideas on how to manage this situation would be greatly appreciated.
A.
UPDATE:
With regards to hsqldb/h2/derby suggestions, I am familiar with them but the company is not ready to go down that route just yet and doing it piecemeal on just one test case won't be suitable.
With regards to my earlier suggestion I would like to elaborate a bit more - consider this scenario:
I want to ensure that my relatively complicated keyword search returns 2100 matches for "John Smith".
In order to find the expected number, I would have analyzed my database and found out the number using a SQL Query. What is the downside of having that query as part of the test, so that you will always know the you are testing the behaviour of the criteria?
So basically the question is: if for some reason you could not have a static data set for testing, how would you perform you integration tests in a non-brittle way?
One approach could be to use in-memory database like Apache Derby or HSQLDB, and prepopulate it with data before test start using DBUnit.
UPDATE: Here is a nice article about the aproach.
I agree with Andrey and Bedwyr that the best approach in the long term is to create an hsqldb database specifically for testing. If you don't have the option of doing that, then your solution seems like an appropriate one. You can't test everything, but you don't want to test nothing either. I've used this approach a few times for testing web services against integration databases etc. But remember that this database has to be maintained as well, if you add new columns etc.
You have to decide what you're trying to test. You don't want to test hibernate, you don't want to test that the database is giving what you've asked for (in terms of SQL). In your tests, you can assume that hibernate works, as does the database.
You say:
We need to unit test this to ensure that the generated query is
correct for various scenarios. One way of testing it -which could be
preferable- would be to test the hibernate criteria is created
correctly by checking it at the end and mocking the database
interaction. However this is not desirable as firstly it's kinda
cheating (it's merely duplicating what the code would be doing) and
also it doesn't check if the criteria itself causes hibernate to barf
or when it goes to database it causes issues.
Why should hibernate barf on the criteria you give it? Because you're giving it the wrong criteria. This is not a problem with hibernate, but with the code that is creating the criteria. You can test that without a database.
It has problems when it gets to the database? Hibernate, in general, creates the sql that is appropriate to the criteria and database dialect you give it, so again, any problem is with the criteria.
The database does not match what hibernate is expecting? Now you are testing that the criteria and the database are aligned. For this you need a database. But you're not testing the criteria any more, you're testing that everything is aligned, a different sort of test.
So actually, it seems to me you're doing an integration test, that the whole chain from the criteria to the structure of the database works. This is a perfectly valid test.
So, what I do is in my tests to create another connection to the database (jdbc) to get information. I execute SQL to get number of rows etc, or check that an insert has happened.
I think your approach is a perfectly valid one.
However, for historical reasons there is no static test database (one that code be checked in as part of the code for example) and the remit of my project does not allow me to embark on creating on
All you need to do is fire up H2 or similar - put some entities in it and execute your integration tests. Once you've done this for a few tests you should be able to extract a data setup utility that creates a schema with some test data that you can use for all the integration tests if you feel the need.
I need to do several integration tests on a Mongo database using Java, and I was looking for a DbUnit-like solution (DbUnit is for Hibernate) that can populate my database with custom data, and reset the state after each run.
Any tips?
Thanks
To start off, I don't know of any direct equivalent to DBUnit for Mongo. Mongo is still a new product, so you'll probably have to "roll your own" for some of this stuff.
However, there are several features of Mongo that should make this easy:
It runs with minimal permissions
It can simply "run" on prepared files
It doesn't really have a schema (except for indexes)
It can work of JSON data
Based on your dataset there are lots of ways to do this. But the basic tools are there.
You should be able to start a version specifically for your test, from your test.
You should be able to import "state" data from JSON file.
You should be able to apply any server-side functions from a JS file (from scratch).
So the whole thing should be pretty straightforward. Though you will have to write much of the glue code.
Here's what I do: connect to a known (often shared) mongo instance, but create a new unique database for each test run using a UUID. You don't have to worry about creating collections, as they are created lazily when you store documents in them for the first time. Create any indexes you need in the constructor of the repository or DAO; mongo index creations succeed immediately without doing any work if the index already exists. Obviously, you don't need to worry about schema migrations ;-)
This scheme requires to you to start from an empty datastore, but it's a known state, so it's easy enough to populate in the setup phase of your tests if need be.
When the test is done, delete the entire database in the teardown phase.
This question has been answered here and permits to start and stop an instance between each test:
https://stackoverflow.com/a/9830861/82609
But start/stop between each test seems to slow down integration tests, and thus you'd better start/stop it for the whole test suite:
https://stackoverflow.com/a/14171993/82609
I know this question is old, but maybe my answer will be useful for someone.
Here is a simple util that I wrote it recently: https://github.com/kirilldev/mongomery
Very simple to populate db with data from json file:
//db here is a com.mongodb.DB instance
MongoDBTester mongoDBTester = new MongoDBTester(db);
mongoDBTester.setDBState("predefinedTestData.json");
To check db state:
mongoDBTester.assertDBStateEquals("expectedTestData.json");
It supports placeholders for expected files which can be useful in some situations.
You can use nosql-unit that has a MongoDB module
When I test DAO module in JUnit, an obvious problem is: how to recover testing data in database?
For instance, a record should be deleted in both test methods testA() and testB(), that means precondition of both test methods need an existing record to be deleted. Then my strategy is inserting the record in setUp() method to recover data.
What’s your better solution? Or your practical idea in such case? Thanks
I'd make a method called createRecord(). It may be a test-method as well. And whenever you need to create a record, call that method from your other test methods.
Maybe DBUnit can help you out.
It allows to have a TEST database in a predefined state before executing each test. Once it set upped, it's really easy to test database driven applications.
A simple solution is to roll back the transaction after the test (for example in tearDown()). That way, the tests can make all the changes they like but they won't change the database (don't forget to turn autoCommit off for the connection).
There is a drawback, though: If a test fails, you can't peek at the database to figure out why. Therefore, most of my tests clean the database before they run and they use autoCommit so I can see the last state where it failed, run a fixed SQL query against the data, etc.
Bozho is correct, of course, but just to add a bit of detail:
If possible, unit tests set up their data before manipulating it, and then clean up after themselves. So ideally you would not be trampling on existing data (perhaps copied from production) for testing, but setting some up as part of the test; that's practically the only way you can be assured that your test will be testing what you intended.