writing a junit test case for the calling of a method - java

i am using eclemma and trying to increase my test coverage:
so far this is my code:
public RolesResponse findRolesByTenant(RolesRequest rolesRequest)
{
RolesResponse rolesResponse = new RolesResponse();
List<Role> roleList = null;
if (StringUtils.isNotBlank(rolesRequest.getTenantCode()))
{
roleList = roleFunctionService.getAllRolesAndFunctionsByTenant(rolesRequest.getTenantCode());
}
if (CollectionUtils.isNotEmpty(roleList))
{
rolesResponse.setRoles(roleList);
}
else
{
rolesResponse.setError(LayerContextHolder.getErrorObject());
}
return rolesResponse;
}
and here is my test:
#Test
public void findRolesByTenantTest()
{
RolesRequest rolesRequest = new RolesRequest();
rolesRequest.setTenantCode("test");
ErrorObject errorObject = new ErrorObject();
RolesResponse rolesResponse = rolesProcessService.findRolesByTenant(rolesRequest);
Assert.assertNull(rolesResponse.getError());
}
the only line eclemma is highlighting in red is this one:
rolesResponse.setError(LayerContextHolder.getErrorObject());
can someone help me in constructing the final test needed to cover this line
thanks

I'm really not a fan of your test anyway - what are you trying to prove by the error being null? That the list came back with something? Also, are you certain that your service will return the result you want in your test every single time?
Don't think of tests in terms of coverage; this will lead to brittle tests and tests that give a false sense of security. What you want to do is write tests that cover each condition that the code could encounter, and the line coverage can follow from that.
From your code, I see two cases.
roleFunctionService#getAllRolesByFunctionAndTenant can return a non-empty list.
It's implied that the resultant rolesResponse#roles contains whatever was in the list provided by the method, and this should be verified.
It's also implied that there is no error set on the object, so it should be null.
roleFunctionService#getAllRolesByFunctionAndTenant can return an empty list
Either the resultant rolesResponse#roles are empty or null; it'd be better if it were empty.
It's implied that there is an error on the object, which is specifically provided by LayerContextHolder.getErrorObject(). You should check to see that it's exactly that.
You'll get to the whole approach of writing this test through the use of a mocking framework.

Related

How can I conduct a JUnit test which relies on the operation of another method?

I wish to conduct a JUnit-4 test for a method that reverts the effect of another method such that the test won't just pass if the first method is broken but instead requires both to work correctly. How can I address this?
Consider my following code...
#Test
public void testRemoveCategory(){
Category newCategory = new Category();
testRecipe.addCategory(newCategory);
testRecipe.removeCategory(newCategory);
assertFalse(testRecipe.getCategories().contains(newCategory));
In this code, the method removeCategory(Category category) can logically only remove a Category if the method addCategory(Category category)\ has already added it. This creates two problems
addCategory must work for removeCategory to pass the test
If addCategory doesn't work, removeCategory WILL pass the test even if it doesn't work either.
I cannot think of a solution to the first problem, but I solved the second problem by using the following code...
#Test
public void testRemoveCategory(){
Category newCategory = new Category();
boolean passesTest;
testRecipe.addCategory(newCategory);
if (!testRecipe.getCategories().contains(newCategory)){
passesTest = false;
}
else
{
testRecipe.removeCategory(newCategory);
if(!testRecipe.getCategories().contains(newCategory))
{
passesTest = true;
}
else
{
passesTest = false;
}
}
assertTrue(passesTest);
}
This however,
is clearly a bad workaround.
still does not solve the first problem.
I can see this general situation occurring often as many methods do serve as inverses of each other. How can I address these issues?
Unit tests are focused on only one unit's behaviour.
testRemoveCategory should not bother if addCategory is working correctly. You may add new categories by reflection, by other methods such as addCategories. You can not test all permutations of the methods.
I do not know the implementation details of how Recipe stores the categories. If the category holder is not passed by constructor or injected, you may try the approach below:
Define the initial state of unit under the test at given block
Try to change the state of unit at when block
And then, Assert the final state
#Test
public void testRemoveCategory() {
// given
Category otherCategory = new Category();
Category newCategory = new Category();
testRecipe.addCategory(otherCategory);
testRecipe.addCategory(newCategory);
// at this point testRecipe should have only two categories: newCategory and otherCategory
// you may add the categories by any other way not only addCategory()
// we are not testing the behaviour of addCategory
// when
testRecipe.removeCategory(newCategory);
// then
// testing the absence of newCategory
assertFalse(testRecipe.getCategories().contains(newCategory));
// testing the presence of otherCategory
assertTrue(testRecipe.getCategories().contains(otherCategory));
// !! but not testing only size of categories
// which may be flaky if there is a bug in removeCategory()
// assertTrue(testRecipe.getCategories().size(), 1);
}
Finally, If and else's are red flags in unit tests.
One should never have to use it.
Hope, it helps.

Does not contain 4 grade - Java

public class Degree {
public Degree(List<Grade> year2, List<Grade> year3) {
if (year2.size() != 4 || year3.size() != 4) {
throw new IllegalArgumentException();
}
}
i have statement for "does not contain 4 grade" to create Junit test. is there a better way to improve this statement (for my knowledge to help me out in future).
#Test(expected = IllegalArgumentException.class)
public void donotcontaingrade() {
List<Grade> year2 = new ArrayList<>();
year2.add(new Grade(1));
year2.add(new Grade(2));
year2.add(new Grade(3));
List<Grade> year3 = new ArrayList<>();
year3.add(new Grade(1));
year3.add(new Grade(2));
year3.add(new Grade(3));
new Degree(year2, year3);
}
Example of my Junit test
Your test would pass, in that the exception would be thrown.
However, you made a common mistake of trying to test multiple issues in one test. You really need four tests for full coverage.
The Happy Path, where your pass in two valid arguments and get back an instance, not an exception.
You pass a bad value and a good value, and get an exception.
You pass a good value and a bad value, and get an exception.
You pass in two bad values and get an exception.
Late addition: When an if statement contains an OR operator, then you can't get 100% coverage in tools. That's because the coverage tool wants to check both conditions false. However, the OR stops checking on the first false, so the second condition is not checked.
To 100% coverage, split the if with OR into two if. The code execution is the same, but the coverage tool will see all code exercised.

JUnit test cases for custom method

I'm studying for my first job interviews as Junior Java Developer and right now I'm trying to learn JUnit test cases. This is an example that I encountered and I must say it's really tricky for me (it's abstract code so I have no idea how to test it).
public class JuiceMaker {
public Juice makeJuice(final List<Fruit> fruits) throws RottenFruitException {
for (final Fruit fruit : fruits) {
if (FruitInspector.isFruitRotten(fruit)) {
throw new RottenFruitException(fruit.getName() + “ is rotten. Cannot make juice.”);
}
}
return Juicer.juice(fruits);
}
}
The only example I managed to create myself is this one:
JuiceMaker jm = new JuiceMaker();
#Test
public void isThrowingException() {
//when
try {
jm.throwsRuntime();
Assert.fail("Expected exception to be thrown");
} catch (RottenFruitException e) {
//then
assertThat(e)
.isInstanceOf(RottenFruitException.class)
.hasMessage((fruit.getName() + " is rotten. Cannot make juice.");
}
}
Any tips of what kind of tests I can perform on this piece of code? Thanks a lot for your help!
Welcome to JUnit, and good luck with your interviews!
First question to ask is what is the contract offered by this class? It takes a list of fruit, tests if any of the fruit are rotten, if so it throws an exception, otherwise it juices them. You can assume the "juice" method is tested elsewhere.
To me, that suggests these tests:
List with single good fruit
List with single rotten fruit
List with several good and one rotten fruit
Empty list
You could also test for null and invalid values, but that might be overdoing things just now.
Once you've decided what to test, then you can start thinking about implementing them. Looks like your implementation has a couple of errors, but you're heading in a good direction. You might find JUnit's "expected" parameter useful for testing for exceptions.
You seem to be instructing the JuiceMaker instance in your test to throw the exception to verify you can catch it.
You have to answer yourself whether that alone will exercise the loop iterating through the list of Fruit and the if() statement.
You can influence the JuiceMaker.makeJuice() better by passing different lists (null, empty, with no rotten fruit, with rotten fruit).
This way you are not forcing any exceptions but causing them - which exercises more paths through your code under test.
If you exercise the above scenarios, you should have a very decent test coverage of your method.
Hope this helps!
The two testcases you put up in your example-answer are going in the right direction, but only half way. Because both tests do not at all test your "class under test".
Reasonable tests would more look like:
public class JuiceMakerTest {
private JuiceMaker underTest;
#Before
public void setup() { underTest = new JuiceMaker; }
#Test(expected=RottenFruitException.class)
public void testThrowsOnRottenFruit() {
underTest.makeJuice(Collections.singletonList("rotten apple"));
}
#Test(expected=???)
public void testWithNullList() {
underTest.makeJuice(null);
}
#Test(expected=???)
public void testWithEmptyList() {
underTest.makeJuice(Collections.emptyList());
}
#Test
public void testXyz() {
Juice expectedResult = ...
assertThat(underTest.makeJuice(Collections.singletonList("apple")), is(expectedResult);
}
and so on. In other words: you follow the nice answer from hugh; and determine the possible ways to invoke your method. The ??? is just a place holder - indicating that you should think up what should happen here. Maybe you expect a specific exception; maybe the method returns a special empty juice ... all up to the contract of the method under test.
You derive error conditions from that, and expected results. And then you write at least one test for of the different aspects you collected.

Test method that returns void

I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.

Junit failed tests, how to fix this?

So I'm tesing using Junit, quite new to it.
I am trying to test methods in a class called SetOfUsers as follows:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "";
SetOfUsers instance = new SetOfUsers();
User expResult = null;
User result = instance.findUserByName(name);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
}
So I wanted to check the name of a user entered in Bob for instance in the name string like this
String name = "Bob";
since I have a user called Bob in the setOfUsers class.
The output window displays this message
Failed: expected:<null> but was:<Staff name:Bob, Staff pass:abc123>
What can I do to make this a pass?
Read about BDD, this is very nice technique for making tests easy to write and understand (read)
Test-driven development is a software development methodology which essentially states that for each unit of software, a software developer must:
define a test set for the unit first;
then implement the unit;
finally verify that the implementation of the unit makes the tests succeed.
Well written test should have GivenWhenThen sections
(Given) some context
(When) some action is carried out
(Then) a particular set of observable consequences should obtain
This style is known as SpecificationByExample
Given-When-Then is a style of representing tests - or as its advocates would say - specifying a system's behavior using SpecificationByExample.
Example test
#Test
public void testFindUserByName() {
// given
SetOfUsers instance = new SetOfUsers();
// when
User result = instance.findUserByName("Bob");
// then
assertEquals("Bob", result.getName());
}
Nice to read:
Arrange Act Assert Alternatives
Maintainable Tests
This test is always going to fail because the last line is
fail("The test case is a prototype.");
The reason your test is failing now is because of the line above,
assertEquals(expResult, result);
You are setting your expected result to null and the result you are getting from the name, "", is probably an empty String as well from that error message. You need to have expResult to be the same as what you expect instance.findUserByName("Bob") to return. However, unless you initialize the instance to be set with a User Object the objects will not match, so it might be better to either mock it to return a pre-created User object so they match, or create a User object with the same properties as the one you expect to be returned check the fields of the User Object returned and the User object you created to be sure they match.
If you want to check for what the user for Bob is, change the code to this:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "Bob";
SetOfUsers instance = new SetOfUsers();
User expResult = <Create an object you expect instance.findUserByName("Bob") to return>;
User result = instance.findUserByName(name);
//Check fields here.
assertEquals(expResult.getUserName(), result,getUserName());
// TODO review the generated test code and remove the default call to fail.
}
You can't test for null using assertEquals().
To test for null, use:
assertNull(result);
I don't understand the question, but if you want to search for "Bob" why you initialize name=""? The test should be:
#Test
public void testFindUserByName() {
//Create SetOfUsers
//Add new User with name Bob
//FindByUsername("Bob")
//AssertEqual(User.getName(), "Bob")
}

Categories

Resources