How to write efficient Junit Test cases in Java? - java

This is the simple code that I have, and I have to write a jUnit test case for the same.
public String deletes() throws Exception {
String deleteSql = "select * from test";
if (isMultiTenant) {
return deleteSql = deleteSql + "and id = ? ";
} else {
return deleteSql;
}
}
so I did it in this way, but somewhere it doesn't look like a good test case its look like simply comparing string between two.
Is there any other way to write test case more meaningful

Most of the unit tests consist of three separate steps:
Data preparation
Execution
Results assertion
There are a lot of people who prefer a test consisted only of the assertion(s):
#Test
public void updateSqlTest() {
assertEquals(
"select * from test",
test.updateSQL()
);
}
This is one way of "looking" the test better in terms of formatting. That's all to discuss here as this kind of test makes no sense to me.
Remember: Don't aim for 100 % code coverage but covering the most important and business-related code. A more meaningful test would be:
Mocking the repository/DAO layer (accessing the database) and test the service layer performing business logic.
Running in-memory database for the purpose of testing (with Spring Boot usually H2 is used as it works very well), fetch and update the data from the database and assert the results.
The test you wrote makes no sense to me. I'd test out the behavior of the SQL query itself and the related business logic that uses it.

Related

Test Case to make sure data cannot be loaded

I have a test case I'm trying to finish. It should try to find location ABC, but that doesn't actually exist in the DB. Essentially, it should not load the data I'm trying to find. I've tried a bunch of things, and haven't figured it out yet. Here is my code:
#Test
public void testFindByInvalidLocABC() {
System.out.println("findByInvalidLocABC");
Storage result = StorageFacadeTest.facade.findByLoc("ABC");
assertNotNull(result);
assertEquals("NOK-0000001402", result.getId());
assertEquals("ABC", result.getLoc());
}
Any suggestions is greatly appreciated!
I have a test case I'm trying to finish. It should try to find
location ABC, but that doesn't actually exist in the DB
To ensure that data be present or not present during test executions, you cannot rely on a applicative or shared database.
Automated tests have to be repeatable. Otherwise, these will be reliable today but useless and error prone tomorrow.
So I encourage you to clean/populate a test database( or schema) before the tests be executed.
Besides, as others commented, your test doesn't look like a "not found" scenario. You assert the retrieved Storage content. It makes no sense.
It should rather look like :
#Test
public void findByLoc_with_invalidLoc_returns_null() {
Storage result = StorageFacadeTest.facade.findByLoc("ABC");
assertNull(result);
}
Some improvements for your unit test:
1) Returning Optional instead of null in the method under test is probably better but you don't use it in your actual implementation. So I follow it in my example.
2) System.out is really not advised in the test code.
3) The test prefix in the test method is not advised either. It is a legacy way as Java annotations didn't exist.

Test a boolean Method in Java

Good afternoon,
i am having troubles with testing a boolean Method.
I have my interface (Dao)
public interface UserDao {
public boolean existUser(String email) throws UserException;
}
And my method is
public boolean existUser(String email) throws UserException {
try{
log.info("Verify exist email " + email);
Map<String, Object> parametersMap = Maps.newHashMap();
parametersMap.put("email", email);
Long count = npTemplate.queryForLong("SELECT count(*) FROM DL_USER WHERE EMAIL = :email", parametersMap);
if(count > 0){
return true;
}
}catch(Exception e){
String errorMsg = "There was an exception trying obtain user id for " + email + " - ERROR " + e.getMessage();
UserException uException = new UserException(errorMsg, e);
throw uException;
}
return false;
}
I would like to test the existUser method.
Create a set of test data comprising arguments to the method of which some should yield true, some false, and others the exception. Call the method with each value in turn and check the actual result with the expected result. Use a database with known content so you know what the expected values should be.
I prefer TestNG for this kind of testing.
Incidentally, the return false; should be inside the try block with the return true. Then you could eliminate the test of a boolean to return a boolean and simply return count > 0;.
There are basically two ways to test this kind of stuff:
a) As Lew already suggested, you could make this an integration test, which means you actually connect to the database, query the user, etc. If you want to be 100% sure, you can even create the user during test initialization and remove the user afterwards (for example by wrapping the whole test in a transaction and doing a rollback at the end). This will prevent your tests from depending on a specific database state or clutter the database with test data.
b) You could also make this a unit test via mocking. For this you would have to mock npTemplate, removing the need for an actual database connection. Then you can verify if npTemplate was called with the correct parameters. Also you can make it return various numbers to test different situations and even let it throw Exceptions to test that. Mockito is the to go framework for this kind of stuff, but there are others as well (for example EasyMock).
The obvious drawback to solution b) is, that you cannot guarantee that your query is actually correct, which doesn't leave much to test. Still, I personally would write both tests, a unit test and a integration test, since the unit test will ensure that the code around your query and the result handling is correct, while the integration test will ensure that your query actually works. (And yes, the integration test will also ensure that the code is correct, but running an integration test often takes far more time, so you can run your unit tests during development all the time and the integration tests only when needed).
And a little P.S., using...
return count > 0;
...will make your code more concise, since you will not have two different places where a return happens.

Should I repeat code in actual class in tests

I want to test that a specific method produces the expected result, but to do that I need to manipulate the input in the test as well.
class ToTest {
public String produceResponse(String input) {
// ....
encryptedIds = encryptIds(input)
output = doStuff(input, encryptedIds)
}
public encryptIds(input) {
....
}
}
In my test I need to check that produceResponse actually produces the expected response.
in order to do that I have to encrypt the ids in the input.
My question is: should I rewrite encryptIds in the test (so that I would have more controller on the result) or should I call encryptIds from the class itself.
Is there a better approach to solve this? I don't like that in my test I know what happens in the specific flow.
If I understand correctly, you would like to test produceResponse() with known encryptedIds as input.
You could do that without refactoring the code, but it would probably be a good idea to refactor it, so that's what I'm going to explain:
class ToTest {
private IdEncryptor encryptor;
public ToTest(IdEncryptor encryptor) {
this.encryptor = encryptor;
}
public String produceResponse(String input) {
String[] encryptedIds = encryptor.encryptIds(input);
return doStuff(input, encryptedIds);
}
}
Now you can unit-test IdEncryptor to test that it produces correct encrypted IDs based on a String input.
And to test the ToTest class, you can mock the IdEncryptor so that whatever the input it receives, it produces the encryptedIds you desire. For example with mockito:
IdEncryptor mockEncryptor = mock(IdEncryptor.class);
when(mockEncryptor.encryptIds(any(String.class)).thenReturn(new String[] {"a", "b"});
ToTest toTest = new ToTest(mockEncryptor);
String response = toTest.produceResponse("input");
// expect that the response is what you expect given "a", "b" as input of doStuff()
Never copy any production code into the unit test as it will get outdated at some point.
If both methods are public, they are part of the public API, so:
you should first unit test the correct behavior of the encryptIds(String) method
then unit test the produceResponse(String) method which will internally use the already tested encryptIds(String) method
If encryptIds(String) would not be part of the public API:
then it is internal implementation and helper method which is not unit testable
produceResponse(String) is then responsible for encryption as a side-effect:
you can still test it if you mark it package private (no modifier)
you can also change the implementation of the encryptIds(String) only for testing purposes
Is encrypting id's something that is integral to your system or not? As it stands this class takes some input and produces some output and as far as your test is concerned this is what's important, no more, no less.
What is the impact of not performing the encryption? If your doStuff method will just fail if it doesn't happen then it is an internal detail to your class-under-test and I wouldn't have the tests care about it at all. If it's a step that absolutely must be performed then I would refactor the code to verify that it absolutely has happened, maybe using a mock as #jb-nizet answered.
As for the general case of duplicating production code in tests, as #Crazyjavahacking stated you should not do this, but I have no issue with using production code from a test- maybe not at a unit level but definitely the higher up the system I go, e.g. when testing writing to a DB I will use the reading code to verify it's happened correctly, but will also have independent tests to verify the reading path as well

mock abstract method of extended class with jmockit

I have a method inside my Dao class like this:
#Override
public List<Dog> loadAllDog(Date pDate) {
final MapSqlParameterSource lParameterSource = new MapSqlParameterSource();
lParameterSource.addValue("jdate", pDate);
final String lSql = readSqlQuery("LAD");
final NamedParameterJdbcTemplate lTemplate = createNamedParameterJdbcTemplate();
return lTemplate.query(lSql, lParameterSource, new DogExtractor());
}
I use the above method to load data for an integration test. Unfortunality the size of the result list is about 300000 data rows.
For my test it is ok to work only with 100 data rows. So I wrote a SQL Test file(Key LAD_TEST) that returns only 100 rows:
SELECT
*
FROM
DOG
WHERE
TO_CHAR(sell, 'dd.mm.yy') = TO_CHAR(:jdate,'dd.mm.yy')
and rownum <= 100
my question is, can I include anyhow that test sql(LAD_TEST) instead of the real production sql(LAD) without changing the production code here final String lSql = readSqlQuery("LAD"); ???
I am using jmockit in my testclass but that dao class(mDogDao) I am talking about is not mocked...
The call from my test:
List<Dog> lAllDog = mDogDao.loadAllDog(lNow.getTime());
Is there any way to manage this with jmockit without mocking mDogDao?
Some advice?
Thx
Stefan
You can mock the NamedParameterJdbcTemplate class, and record an expectation so the query(...) method returns your desired test data.
Why would you want to query your live database in a unit test?
What I always do is work against a seperate unit test database schema or an in-memory database. That way I am certain that a bug in my queries doesn't influence the data used by other people.
Even if you need a certain amount of test-data, you can always insert an extract of your data before your test and clean it up afterwards.
Moreover this way your unit tests are also run in isolation. If one tests modifies data, your other tests don't suffer from the possible consequences.

Tests granularity when using mock object

I have Struts 1 action and want to test it in isolation.
What this action do is as follows:
load data using parameters from request
build xml-based representation of this data
send this response directly to client
I use jMock for testing but have one doubt here.
My first test is
public void shouldActionInvocationPrintValidResponse() {
ProcessingAction action = new ProcessingAction();
DBService service = mock(DBService.class);
List records = new ArrayList();
when(service.loadData()).thenReturn(records);
ResponseBuilder builder = mock(ResponseBuilder.class);
when(builder.buildResponse(records)).thenReturn("fake response");
action.execute(null, null, null, null);
assertEquals("fake response", writer.getContentWritten());
}
And my prod code evaluated to this:
public String execute(...) {
List recordsList = service.loadData();
String response = responseBuilder.buildResponse(recordsList);
response.getWriter().print(response);
}
My doubt here is if such test isn't too big here. I check whole succesful flow here. Shouldn't there be separate tests for checking every single dependency call in their own tests?
I wonder because I had troubles with this test's name. My ideas at the beginning were something like
shouldFetchDataThenFormatThemAndSendResponse
As this is all the tests does, the name shows it probably does too much (look at the "and" e.g. in the test name)
And should I have whole test written at once, or just add dependencies calls step-by-step?
EDIT:
Detailed code for test and action provided.
I think you are on the right track. shouldFetchDataThenFormatThemAndSendResponse This says it all. In your test naming you are talking about implementation details. This is how your first test should have been written.
ProcessingAction action = new ProcessingAction();
Response response = action.execute();
assertEquals(true, response.IsValid);
Try: shouldGetResponseWhenActionExecuted.
Now you can look at how to get a response when executing an action.
I would bet you dollars to donuts that you didn't TDD this.
Remember: Intent over Implementation! Stop showing your crusty underwear.
It is hard to answer your question without seeing the code however I will give it a stab. For the test to be a Unit test, it should not exercise code other than the code in the class under test. If you have mocked every other class that the action calls and what you are verifying is only being done within the class under test, then no the test is not too big. I have written unit tests that have a large number of verification statements because all the things happen in the class under test due to the single invocation of the method.
My unit test rules are:
1. Exercise code only in the class under test
2. Only enter the method under test once per test method
I agree with John B.
Also, if you use the Mock Test Runner and write it correctly, you may not need an assertion.

Categories

Resources