How to perform Junit tests without affecting real data? - java

I am currently been assigned to creating Junit tests for a project. I created some test, however after reading up on some best practices I discovered that Junit tests should not affect real data as it can comprise integrity of the data.
One test for example below tests the Editing of an existing user's data in the repository:
#Test
void EditUserTest()
{
UserController userController = new UserController();
List<User> userList = (List<User>) userController.getCurrentUserlist();
RoleController roleController = new RoleController();
List<Role> roleList = (List<Role>) roleController.GetCurrentRolelist();
User selectedUser = userList.get(0);
selectedUser.setLoginName("EditedLoginName");
selectedUser.setFirstName("EditedFirstName");
selectedUser.setLastName("EditedLastName");
selectedUser.setEmployeeID(555555555);
selectedUser.setRole(roleList.get(6));
selectedUser.setAutoLogoutPeriod(6);
selectedUser.setEksSerial("45f869");
selectedUser.setEksLevel(9);
User NonExistent = new User();
assertTrue(userController.EditUser(selectedUser), "Testing edit to User in repository");
assertFalse(userController.EditUser(NonExistent), "Testing edit to Non-Existent User in repository");
User editedUser = userController.GetUser(selectedUser.getID());
assertEquals("EditedLoginName", editedUser.getLoginName(), "Testing edit to User Login name");
assertEquals("EditedFirstName", editedUser.getFirstName(), "Testing edit to User First name");
assertEquals("EditedLastName", editedUser.getLastName(), "Testing edit to User Last name");
assertEquals(55555555, editedUser.getEmployeeID(), "Testing edit to User Employee ID");
assertEquals(roleList.get(6), editedUser.getRole(), "Testing edit to User Role");
assertEquals("45f869", editedUser.getEksSerial(), "Testing edit to User Eks Serial");
assertEquals(9, editedUser.getEksLevel(), "Testing edit to User Eks Level");
}
As you can see I retrieve a list of the current users within the repository and just take the first one. After changing its values I then make the actual edit to the repository using the controller and later retrieve the same user from the repository to compare and see if an edit was actually made. Now how would I test this same thing without actually affecting the real data within the repository?

Unit tests are not supposed to access real data. You need to mock any such data so that the real data is not affected.
The purpose of unit tests is to test the functionality, it isn't dependent on the real data.
You can look into Mockito for mocking objects that exhibit the behavior of actual objects.
This link might be helpful: Official docs

If you are writing unit tests then your tests should only focus on the components you are testing, which means if you are testing controller layer you should not call service or dao layer and use their functionalities.
Let's say you want to test your controller then, you should mock the service layer using Mockito or any other test framework. By mocking you are basically avoiding actual service call and continue with your controller level testing.
This example will help

Related

Unit testing mocking interactions

I'm trying to implement unit testing for a large enterprise app that has multiple layers and interactions between classes.
Reading about this type of test, I see that it is not recommended to verify interaction, you should test "observable results". For example:
public void Purchase_succeeds_when_enough_inventory(){
var storeMock = new Mock<IStore>();
storeMock.Setup(x => x.HasEnoughInventory(Product.Shampoo, 5)).Returns(true);
var customer = new Customer();
bool success = customer.Purchase(storeMock.Object, Product.Shampoo, 5);
Assert.True(success);
storeMock.Verify(x => x.RemoveInventory(Product.Shampoo, 5),Times.Once);
}
In this case, verifying that RemoveInventory is called it's wrong (according to the theory), because it is an implementation detail.
Now, how should I test that the product has been removed from the inventory, given that the database or dao classes are mocked? There's no way to know, other than check that the function that does remove the product is called and hope for the best.
What am I missing here? Should I implement this in a different manner?

Can you run JUnit Tests for a CLI application?

I am relatively new to unit tests in Java and I made an application completely with CLI. Example once starting the application the user is given a set of options like so.
Register
Login
.
.
. Etc etc.
If he choses to login he is transferred to a Register () method that asks for details such as name and surname inside the method itself.
I want to know if there is any way lf simulating user input when creating the unit tests or if I have to override the methods so that I can pass values through the arguments and do unit testing that way.
Ideally your code should be written so that it's easy to test, and the method of input doesn't matter. This means that the input should be separated from the business logic, so that when you're writing the tests, you can ignore the input part completely.
For example instead of having a global Scanner and having something like the following, which makes the method dependent on the input method
public void login() {
String username = scanner.nextLine();
// check that the username is valid
}
a more testable method without any dependencies to the input method would be
public void login(String username) {
// check that the username is valid
}
also make sure you understand what constitutes a correct unit test. For this method the obvious tests would be that you can login with valid credentials, and that you can't login with invalid credentials.

Java Mock data base for testing Spring application

I have made simple application for study perpose and i want to write some unit/intagration tests. I read some information about that i can mock data base insted of create new db for tests. I will copy the code which a write. I hope that some one will explain me how to mock database.
public class UserServiceImpl implements UserService {
#Autowired
private UserOptionsDao uod;
#Override
public User getUser(int id) throws Exception {
if (id < 1) {
throw new InvalidParameterException();
}
return uod.getUser(id);
}
#Override
public User changeUserEmail(int id, String email) {
if (id < 1) {
throw new InvalidParameterException();
}
String[] emailParts = email.split("#");
if (emailParts[0].length() < 5) {
throw new InvalidParameterException();
} else if (!emailParts[1].equals("email.com")) {
throw new InvalidParameterException();
}
return uod.changeUserEmail(id, email);
}
This above i a part of the code that i want to test with the mock data base.
Generally you have three options:
Mock the data returned by UserOptionsDao as #Betlista suggested, thus creating a "fake" DAO object.
Use an in-memory database like HSQLDB to create a database with mock data when the test starts, or
Use something like a Docker container to spin up an instance of MySQL or the like and populate it with data, so you can restart it as necessary.
None of these solutions are perfect.
With #1, your test will skip the intermediate steps of authenticating to the database and looking for data. That leaves a part of your code untested, and as they say, "the devil is in the details." Often people run into problems when they mock DAO's like this when they try to deploy.
With #2, you connect to an actual database, but you have to make sure that either you are using the exact same type of database in your production code or something compatible. It also makes debugging a pain because you have to pause the test to see the contents of the database if something goes wrong.
With #3, you avoid all the problems with #1 and #2, but then you have to wire up all the Docker stuff. (I'm doing this right now, and I'm having problems too). The advantage, though, is that like #2 you can set up all of your test data at once, and be guaranteed that the production database you choose will be exactly the same as your unit test.
In your case, I would go with #2 since the application is for study purposes. Yes, I know this is a long-winded answer, but as you gain experience, you will probably want to know how to "scale up."
What you can do very easily is to have your implementation of UserOptionsDao in test package and set this one to UserServiceImpl. This new implementation can return fixed set of data for example...
This is a highlevel idea. You probably do not want to have many implementations (different for each test in general), so you should use some mocking framework like Mockito or EasyMock, look at the documentation for more details.

should gui be visible during unit testing?

I am unit testing my application with JUnit. It uses (or tries to use...) the MVP pattern, hibernate and a swing gui.
In my test, I am testing whether persistence works as expected, e.g. is the date format correct, are the relationships between the database tables correct, etc.
Here's an (edited) example:
#Test
public void testCheckBeitragCalculation() {
MainView view = new MainView();
view.initGUI();
Controller persist = new Controller(view);
persist .saveData(testObject);
Controller edit = new Controller(view);
Controller search = new Controller(edit);
search.getData("10001"); // primary key
TestObject t2 = edit.getViewData();
assertEquals(10, t2.getBeitrag());
}
I initiate the main view because two controllers needs a reference to the main view to pass data.
Controller persist persists the object, Controller edit is the controller for the editing view and Controller search needs a reference to edit because it looks up an entity in the database and then displays this data in the editing view through the edit controller.
Because these controllers display the data in the GUI, the GUI shows up a split second during the unit test.
Is that bad practice? I've read that you shouldn't test GUI code, but I'm not testing the GUI itself, it just gets called by the tested code.
Thanks for advice!
There is no right answer to this. In general if it solves your purpose then you can go ahead with this but again if in future your product build system adds these junit test cases to execute after each build through scheduled daily build (e.g. jenkins) and the box where build runs (generally some server) doesn't support any UI (or it is not available at that particular time) like XWindows then your test might fail.

Database cleanup after Junit tests

I have to test some Thrift services using Junit. When I run my tests as a Thrift client, the services modify the server database. I am unable to find a good solution which can clean up the database after each test is run.
Cleanup is important especially because the IDs need to be unique which are currently read form an XML file. Now, I have to manually change the IDs after running tests, so that the next set of tests can run without throwing primary key violation in the database. If I can cleanup the database after each test run, then the problem is completely resolved, else I will have to think about other solutions like generating random IDs and using them wherever IDs are required.
Edit: I would like to emphasize that I am testing a service, which is writing to database, I don't have direct access to the database. But since, the service is ours, I can modify the service to provide any cleanup method if required.
If you are using Spring, everything you need is the #DirtiesContext annotation on your test class.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/test-context.xml")
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
....
}
Unless you as testing specific database actions (verifying you can query or update the database for example) your JUnits shouldn't be writing to a real database. Instead you should mock the database classes. This way you don't actually have to connect and modify the database and therefor no cleanup is needed.
You can mock your classes a couple of different ways. You can use a library such as JMock which will do all the execution and validation work for you. My personal favorite way to do this is with Dependency Injection. This way I can create mock classes that implement my repository interfaces (you are using interfaces for your data access layer right? ;-)) and I implement only the needed methods with known actions/return values.
//Example repository interface.
public interface StudentRepository
{
public List<Student> getAllStudents();
}
//Example mock database class.
public class MockStudentRepository implements StudentRepository
{
//This method creates fake but known data.
public List<Student> getAllStudents()
{
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(...));
studentList.add(new Student(...));
studentList.add(new Student(...));
return studentList;
}
}
//Example method to test.
public int computeAverageAge(StudentRepository aRepository)
{
List<Student> students = aRepository.GetAllStudents();
int totalAge = 0;
for(Student student : students)
{
totalAge += student.getAge();
}
return totalAge/students.size();
}
//Example test method.
public void testComputeAverageAge()
{
int expectedAverage = 25; //What the expected answer of your result set is
int actualAverage = computeAverageAge(new MockStudentRepository());
AssertEquals(expectedAverage, actualAverage);
}
How about using something like DBUnit?
Spring's unit testing framework has extensive capabilities for dealing with JDBC. The general approach is that the unit tests runs in a transaction, and (outside of your test) the transaction is rolled back once the test is complete.
This has the advantage of being able to use your database and its schema, but without making any direct changes to the data. Of course, if you actually perform a commit inside your test, then all bets are off!
For more reading, look at Spring's documentation on integration testing with JDBC.
When writing JUnit tests, you can override two specific methods: setUp() and tearDown(). In setUp(), you can set everything thats necessary in order to test your code so you dont have to set things up in each specific test case. tearDown() is called after all the test cases run.
If possible, you could set it up so you can open your database in the setUp() method and then have it clear everything from the tests and close it in the tearDown() method. This is how we have done all testing when we have a database.
Heres an example:
#Override
protected void setUp() throws Exception {
super.setUp();
db = new WolfToursDbAdapter(mContext);
db.open();
//Set up other required state and data
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
db.dropTables();
db.close();
db = null;
}
//Methods to run all the tests
Assuming you have access to the database: Another option is to create a backup of the database just before the tests and restore from that backup after the tests. This can be automated.
If you are using Spring + Junit 4.x then you don't need to insert anything in DB.
Look at
AbstractTransactionalJUnit4SpringContextTests class.
Also check out the Spring documentation for JUnit support.
It's a bit draconian, but I usually aim to wipe out the database (or just the tables I'm interested in) before every test method execution. This doesn't tend to work as I move into more integration-type tests of course.
In cases where I have no control over the database, say I want to verify the correct number of rows were created after a given call, then the test will count the number of rows before and after the tested call, and make sure the difference is correct. In other words, take into account the existing data, then see how the tested code changed things, without assuming anything about the existing data. It can be a bit of work to set up, but let's me test against a more "live" system.
In your case, are the specific IDs important? Could you generate the IDs on the fly, perhaps randomly, verify they're not already in use, then proceed?
I agree with Brainimus if you're trying to test against data you have pulled from a database. If you're looking to test modifications made to the database, another solution would be to mock the database itself. There are multiple implementations of in-memory databases that you can use to create a temporary database (for instance during JUnit's setUp()) and then remove the entire database from memory (during tearDown()). As long as you're not using an vendor-specific SQL, then this is a good way to test modifying a database without touching your real production one.
Some good Java databases that offer in memory support are Apache Derby, Java DB (but it is really Oracle's flavor of Apache Derby again), HyperSQL (better known as HSQLDB) and H2 Database Engine. I have personally used HSQLDB to create in-memory mock databases for testing and it worked great, but I'm sure the others would offer similar results.

Categories