Test a boolean Method in Java - 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.

Related

How to write efficient Junit Test cases in 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.

how can I test a void method that insert a record in database using Junit?

I have a method that calls another method to retrieve data and insert it into the database, how can I test this method in Junit since this method retrieve nothing? Can anyone provide me some example of this situation?
public static void method(){
User user = getUser();
try {
String Query = "INSERT INTO users (USER_ID , Name) VALUES ("
+user.getID()+","+user.getName()+")";
Statement statement = conn.createStatement();
statement.executeUpdate(Query);
} catch (Exception e) {
e.printStackTrace();
}
}
I was thinking to use mock object for user, but I'm not sure how can I check if the user is inserted to the database. please help.
There are few pointers here but before that, you have to be sure about what's the code under test. The reason I say this is because that will actually make you refactor your code a lot.
For example, for the code below:
public static void method(){
User user = getUser();
try {
String query = "INSERT INTO users (USER_ID , Name) VALUES ("
+user.getID()+","+user.getName()+")";
Statement statement = conn.createStatement();
statement.executeUpdate(query);
} catch (Exception e) {
e.printStackTrace();
}
}
you might want to test following:-
Whether the query string is created properly i.e. a valid SQL as expected?
Should the method never throw an exception as we want to catch all the checked exception?
All the resources are closed once the work is done? e.g. in your method connection is opened but never closed.
Now out of above points, there could be some points with higher importance e.g. ensuring query is built correctly.
So, for that, the query builder code should be pulled out of this method and now you could easily test this query in the separate unit test.
Similarly, you would want to make sure a connection is closed after its job is completed. Hence, you might want to extract this code to a method that accepts a query as param, open connection, performs DB CRUD closes the connection and returns the output. And make sure that you are not repeating this code all the time in different methods.
Now, let's go to the pointers:-
If you at any point think that there is some code inside a method that's not testable till that code is part of the method. Please pull it out to a public / private method and test it.
Never try to test DB persistence as part of a unit test. The DB drivers etc are already having their own tests and are globally used.
If you think your method needs to be tested for whether it is called as many times as expected (it's what you want to test). It's called interaction based testing
You could use mocking (Mockito) and stub out the method under test and then assert how many times the method should be called. See this and this link.
Hope it helps!
Classes should be tested against the expected behavior.
Here testing the return type (even if it had other thing as void) makes no sense.
Your method performs a SQL query.
So your unit test has to assert the expected side effect on the database : an insertion with the expected values.
Note that to have reproducible and fast tests, you should favor embedded databases for unit testing.

How to properly write JUnit tests?

I'm a bit confused on how to properly write unit tests for my application.
Actually i want to know if i have to rewrite an existed method and modify it for junit or just call my existed method and use assert.
So far, i use the second option, but i've came across with a problem.
For example, inside a Controller method i'm getting the currently logged in user and pass it to some services. If i call this method through JUnit it will show null exception because there is no logged in user.
So,
1) do i have to rewrite these kind of methods for testing purposes?
2) Is it proper to call existed methods and use assertion anyway?
Thanks
#RequestMapping(value="/like", method=RequestMethod.GET)
public String msgLike(#RequestParam("msgId") long messageId, #RequestParam("like") boolean like){
User user = new User();
user = this.userService.getUserByName(this.userService.getLoggedInUsername()); //NULL EXCEPTION HERE WHEN TESTING
if(!messageService.checkIfLiked(user, messageId)){
if(like){
messageService.insertLike(messageId);
messageService.insertMessageUserLike(user, messageId);
}
if(!like){
messageService.insertDislike(messageId);
messageService.insertMessageUserLike(user, messageId);
}
}
return "redirect:/home";
}
Actually i want to know if i have to rewrite an existed method and modify it for junit or just call my existed method and use assert.
Just call your exiting method, In fact junit is written before writing logic for calling method.
Example:
If you want to test int square(int num) method, which find square of given num,
So write Junits like this ,
#Test
squareTest() {
int square = objectName.square(3);
assertThat(square , is(equalTo(9)));
}
And when coding done like this,
int square(int a) {
result=a*a;
return result;
}
Run your Junit.
For your second question,
You will have to read Mocking.
In your case you are trying to test a rest controller which is slightly different when testing normal methods. For example the following method:
public MyClass{
public static int sum(int a, int b){
return a + b;
}
}
Could simply be tested by:
#Test
public void testSum(){
assertEquals(3, MyClass.sum(1, 2));
}
But in your case you require the controller api to be used properly. i.e. you require a logged in user. For this you would need to test your controllers by accessing them as users would. This provides some explanation on the process and this answer provides even more details.
Essentially what you are looking for is unit testing rest controllers.
What you need to do is in testing, supply a fake userService that will give the function a User with properties relevant for that test.
Before the test, you need to set this.userService to your FakeUserService.
It's hard to be more specific without seeing more of your code.
This is a good question because this is a common problem when learning to write unit tests. Solving this problem will help you write better code.

Junit testing in a Spring / Maven project

I have a problem writing a Junit testcase for a Spring project. Its about the following method;
boolean doesUserIdExist(String userId){
if(userRepository.findOne(userId.toLowerCase()) != null) {
throw new userAlreadyExistsException("User with id: " + userId + " already exists")
return false;
}else{
return true;
}
}
Now in my jUnit I have something written like this..:
void compareDuplicateUserIdTest (){
UserService UserService = new UserService();
String lowercase = "test";
String uppercase = "Test";
boolean result = userService.doesUserIdExist(lowercase);
//Check the boolean result if its true
}
Since im using the findOne method it means that i'd have to check the String = "test" against the DB userId = "test". This is not the right way since it should work standalone without any records in the MongoDB database.
Now i've been reading about a framework like mockito to test this, but isn't this "too much" for such a simple method check? Can I remove the findOne part and just compare the strings?
You are facing a very common problem for unit testing where databases should not be involved (that would be integration testing), so... here is where Mockito is a great tool to use.
Using Mockito allows you to mock your database results and continue with the regular flow of your method, so you could do something like this:
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class UserService_doesUserIdExistTests
{
#Mock
private UserRepository userRepository;
#InjectMocks
private UserService userService;
#Test
void compareDuplicateUserIdTest() {
String lowercase = "test";
// Mocking the response for your method that uses external dependencies
when(userRepository.findOne(lowercase)).thenReturn(true); // You can mock the response you want using .thenReturn(...)
// Test your userService method (you can also debug it if needed)
boolean result = userService.doesUserIdExist(lowercase);
//Check the boolean result if its true
assertTrue(result);
}
}
I have not tested the code but shows the idea of testing userService.doesUserIdExist(...) method as a unit. Also this is quite helpful when you need to learn by debugging code.
No, it is not too much. The idea of Unit tests is to test method behaviour based on different inputs and insure it behaves as expected. It also documents your expectations and makes refactoring much less painful.
Imagine in the future somebody (may be even you) will decide to remove userRepository.findOne from doesUserExist method. Your unit test will fail and then the developer will have to figure out if the tests need to be changed due to rafactoring or the refactoring needs to be fixed.
I am not even sure what you'll be testing if you remove findOne method and how you are planning to do that.
Mockito and Spring make mocking really simple. All you need to do is define and initiate mock userRepository and then define the behaviour based on the input.

JUnit4 fail() is here, but where is pass()?

There is a fail() method in JUnit4 library. I like it, but experiencing a lack of pass() method which is not present in the library. Why is it so?
I've found out that I can use assertTrue(true) instead but still looks unlogical.
#Test
public void testSetterForeignWord(){
try {
card.setForeignWord("");
fail();
} catch (IncorrectArgumentForSetter ex){
}
// assertTrue(true);
}
Call return statement anytime your test is finished and passed.
As long as the test doesn't throw an exception, it passes, unless your #Test annotation specifies an expected exception. I suppose a pass() could throw a special exception that JUnit always interprets as passing, so as to short circuit the test, but that would go against the usual design of tests (i.e. assume success and only fail if an assertion fails) and, if people got the idea that it was preferable to use pass(), it would significantly slow down a large suite of passing tests (due to the overhead of exception creation). Failing tests should not be the norm, so it's not a big deal if they have that overhead.
Note that your example could be rewritten like this:
#Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
card.setForeignWord("");
}
Also, you should favor the use of standard Java exceptions. Your IncorrectArgumentForSetter should probably be an IllegalArgumentException.
I think this question needs an updated answer, since most of the answers here are fairly outdated.
Firstly to the OP's question:
I think its pretty well accepted that introducing the "expected excepetion" concept into JUnit was a bad move, since that exception could be raised anywhere, and it will pass the test. It works if your throwing (and asserting on) very domain specific exceptions, but I only throw those kinds of exceptions when I'm working on code that needs to be absolutely immaculate, --most APIS will simply throw the built in exceptions like IllegalArgumentException or IllegalStateException. If two calls your making could potentitally throw these exceptions, then the #ExpectedException annotation will green-bar your test even if its the wrong line that throws the exception!
For this situation I've written a class that I'm sure many others here have written, that's an assertThrows method:
public class Exceptions {
private Exceptions(){}
public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
try{
actionThatShouldThrow.run();
fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
}
catch(Exception e){
if ( ! expectedException.isInstance(e)) {
throw e;
}
}
}
}
this method simply returns if the exception is thrown, allowing you to do further assertions/verification in your test.
with java 8 syntax your test looks really nice. Below is one of the simpler tests on our model that uses the method:
#Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
//setup
AxisRange range = new AxisRange(0,100);
//act
Runnable act = () -> range.setLowerBound(200);
//assert
assertThrows(IllegalArgumentException.class, act);
}
these tests are a little wonky because the "act" step doesn't actually perform any action, but I think the meaning is still fairly clear.
there's also a tiny little library on maven called catch-exception that uses the mockito-style syntax to verify that exceptions get thrown. It looks pretty, but I'm not a fan of dynamic proxies. That said, there syntax is so slick it remains tempting:
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
// then: catch the exception if any is thrown
catchException(myList).get(1);
// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;
Lastly, for the situation that I ran into to get to this thread, there is a way to ignore tests if some conidition is met.
Right now I'm working on getting some DLLs called through a java native-library-loading-library called JNA, but our build server is in ubuntu. I like to try to drive this kind of development with JUnit tests --even though they're far from "units" at this point--. What I want to do is run the test if I'm on a local machine, but ignore the test if we're on ubuntu. JUnit 4 does have a provision for this, called Assume:
#Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
//this line will cause the test to be branded as "ignored" when "isCircleCI"
//(the machine running ubuntu is running this test) is true.
Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
//an ignored test will typically result in some qualifier being put on the results,
//but will also not typically prevent a green-ton most platforms.
//setup
URL url = DLLTestFixture.class.getResource("USERDLL.dll");
String path = url.toURI().getPath();
path = path.substring(0, path.lastIndexOf("/"));
//act
NativeLibrary.addSearchPath("USERDLL", path);
Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
//assert
assertThat(dll).isNotNull();
}
I was looking for pass method for JUnit as well, so that I could short-circuit some tests that were not applicable in some scenarios (there are integration tests, rather than pure unit tests). So too bad it is not there.
Fortunately, there is a way to have a test ignored conditionally, which actually fits even better in my case using assumeTrue method:
Assume.assumeTrue(isTestApplicable);
So here the test will be executed only if isTestApplicable is true, otherwise test will be ignored.
There is no need for the pass method because when no AssertionFailedException is thrown from the test code the unit test case will pass.
The fail() method actually throws an AssertionFailedException to fail the testCase if control comes to that point.
I think that this question is a result of a little misunderstanding of the test execution process. In JUnit (and other testing tools) results are counted per method, not per assert call. There is not a counter, which keeps track of how many passed/failured assertX was executed.
JUnit executes each test method separately. If the method returns successfully, then the test registered as "passed". If an exception occurs, then the test registered as "failed". In the latter case two subcase are possible: 1) a JUnit assertion exception, 2) any other kind of exceptions. Status will be "failed" in the first case, and "error" in the second case.
In the Assert class many shorthand methods are avaiable for throwing assertion exceptions. In other words, Assert is an abstraction layer over JUnit's exceptions.
For example, this is the source code of assertEquals on GitHub:
/**
* Asserts that two Strings are equal.
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null) {
return;
}
if (expected != null && expected.equals(actual)) {
return;
}
String cleanMessage = message == null ? "" : message;
throw new ComparisonFailure(cleanMessage, expected, actual);
}
As you can see, in case of equality nothing happens, otherwise an excepion will be thrown.
So:
assertEqual("Oh!", "Some string", "Another string!");
simply throws a ComparisonFailure exception, which will be catched by JUnit, and
assertEqual("Oh?", "Same string", "Same string");
does NOTHING.
In sum, something like pass() would not make any sense, because it did not do anything.

Categories

Resources