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.
Related
I'm writing testcases for below given method.
Method:
#Override
public void removeAllConnections(String uuid, String userName, String oimId) {
customLogger.debug(Thread.currentThread().getStackTrace()[1].getMethodName(), userName, null, null, accessProviderBuilder.getUserName(), accessProviderBuilder.getUuid());
UserAccessBean userAccessBean = new UserAccessBean(userName);
userAccessBean.setOimid(oimId);
userAccessBean.setToken("");
log.info("removeAllConnections:oimid:"+userAccessBean.getOimId());
UserProfileDetailBean userProfileDetail = accessClient.getAccess(userAccessBean,applicationForCsr);
Set<AccountAccess> accountAccesses = userProfileDetail.getAccountAccessList();
try {
removeAllConnectionsExceptPrimary(oimId, userName, accountAccesses);
removePrimaryConnection(oimId, userName, accountAccesses);
} catch (ConnectionStateException e) {
throw new ConnectionStateException(ConnectionNameNotRemoved, CONNECTION_REMOVAL_FAILED_MSG);
} catch (InternalServerErrorException e) {
throw new InternalServerErrorException(INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR_MSG);
}
}
Below snippet is test case for given method.
Testcase:
#Test
public void testRemoveAllConnections() {
UserAccessBean userAccessBean = new UserAccessBean(userName);
when(accessClient.getAccess(userAccessBean,"CSR")).thenReturn(userProfileDetail);
when(userProfileDetail.getAccountAccessList()).thenReturn(accountAccesses);
String applicaionForCSR = "CSR";
ReflectionTestUtils.setField(service, "applicationForCsr", applicaionForCSR);
service.removeAllConnections(uuid, userName, oimId);
}
While debugging the code, my execution is failing at below given line as the value of userProfileDetail is null.
Set<AccountAccess> accountAccesses = userProfileDetail.getAccountAccessList();
While doing inspect element on accessClient.getAccess(userAccessBean,applicationForCsr) it is throwing below error. Pretty sure it is some silly mistake but unable to trace it.
Error:
No such instance method: 'UserProfileDetailBean
v1.AccessService$$EnhancerByMockitoWithCGLIB$$a852895d.getAccess
(UserAccessBean)'
Application: Spring Boot 1.5.0
Library: Mockito 2.7.X
I can suggest three possible solutions (or more like 2.5):
a) Override the equals method of UserAccessBean, so that two UserAccessBeans are equal if and only if their names are equal. Of course, this might interfere with your productive code and I would not change the equals method only for testing.
b) Since the username doesn't actually play a vital role in your test (the tests itself defines what the username is), you can simply ignore the details with...
when(accessClient.getAccess(Mockito.any(UserAccessBean.class),Mockito.eq("CSR"))).thenReturn(userProfileDetail);
This way, the userProfileDetail will be returned for any value of the first parameter. Of course, you lose detail here, so for example, the test would be correct if the username was somehow wrong, but chances are that this isn't possible in your test anyway.
Mockito.any(...) is a so called matcher that tells Mockito to "use" this rule no matter what value is given for the parameter in question. Anything you put there is ok for Mockito. Mockito.eq("CSR") tells it, that this parameter must be equal to "CSR". So, the whole rule is...
If someone calls accessClient.getAccess, no matter what the first parameter ist, but the 2nd must be equal to "CSR", then return userProfileDetail.
So, with this, the first parameter can be anything. So, for example, the following to calls will be accepted:
accessClient.getAccess(new UserAccessBean("correct name"), "CSR");
accessClient.getAccess(new UserAccessBean("totally wrong name"), "CSR");
...because it does not matter what the first parameter is, ANY value will be accepted. So, what you "lose" there is the ability to check if the UserAccessBean is the correct one (because any is accepted). But in your case, since you only define those UserAccessBeans in the test anyway, this should not be a problem.
But if it is, I can offer two workarounds...
c) Use either a customer Matcher (that checks the name of the UserAccessBean) or use the Mockito.any(...) as above and an ArgumentCaptor to check if the name was correct in the end...
ArgumentCaptor<UserAccessBean> captor = ArgumentCaptor.forClass(UserAccessBean.class);
Mockito.verify(accessClient).getAccess(captor.capture(),Mockito.eq("CSR"));
assertEquals(captor.getValue().getName(), "myName");
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.
I have a utility method used in hundreds of tests to mock the return value from a customised randomiser. Here's a (highly artificial) model of my code:
interface CardRandomiser{
Card getCard(Suit suit);
}
void mockCard(Suit suit, Face face) {
CardRandomiser rand = mock(CardRandomiser.class);
when(rand.getCard(suit)).thenReturn(new Card(suit, face));
Game.setCardRandomiser(rand);
}
This can then be used as:
mockCard(Suit.CLUBS, Face.QUEEN);
Card card = pickACardAnyCard();
assertThat(card.getFace(), is(Face.QUEEN));
However this makes some bugs a bit hard to pick up. If the method under test incorrectly asks for Suit.HEARTS then the mock returns null and the assertion correctly fails. But it's impossible to tell through the error message what was passed to the mock.
Clearly I could handle this with a verify. I could pass the mock back out of mockCard function and then separately verify that is was called with the correct value. But that really clutters up the tests assertions that are not really related to what's being tested. Given every time this method is called I am specifying an expected argument value I'd prefer to put the assertion in one place. Note that this all occurs before the method under test is called.
Ideally I'd like the when statement to throw an exception if it's called with an unexpected value. Something like:
when(rand.getCard(suit)).thenReturn(new Card(suit, face));
when(rand.getCard(intThat(not(is(suit))))).thenThrow(new IllegalArgumentException());
This works and stops the test when getCard is called which is better. But it still doesn't allow me to show what the incorrect argument was.
I also tried it using an ArgumentCaptor and then checking the captured value. But it's clear they are for verify statements rather than when statements.
Is there a standard Mockito way of doing this, or do I need to clutter my tests with verify statements?
You can configure mockito answer using thenAnswer, e.g.
private CardRandomiser mockCard(final Suit suit, final Face face) {
CardRandomiser rand = mock(CardRandomiser.class);
when(rand.getCard(any(Suit.class))).thenAnswer(new Answer<Card>() {
#Override
public Card answer(InvocationOnMock invocation) throws Throwable {
if(!suit.equals(invocation.getArguments()[0])) {
throw new IllegalArgumentException(
String.format("Value %s passed, but mocked for %s", invocation.getArguments()[0], suit));
}
return new Card(suit, face);
}
});
return rand;
}
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.
I want to use Mockito to test the (simplified) code below. I don't know how to tell Mockito to fail the first time, then succeed the second time.
for(int i = 1; i < 3; i++) {
String ret = myMock.doTheCall();
if("Success".equals(ret)) {
log.write("success");
} else if ( i < 3 ) {
log.write("failed, but I'll try again. attempt: " + i);
} else {
throw new FailedThreeTimesException();
}
}
I can setup the success test with:
Mockito.when(myMock).doTheCall().thenReturn("Success");
And the failure test with:
Mockito.when(myMock).doTheCall().thenReturn("you failed");
But how can I test that if it fails once (or twice) then succeeds, it's fine?
From the docs:
Sometimes we need to stub with different return value/exception for the same method call. Typical use case could be mocking iterators. Original version of Mockito did not have this feature to promote simple mocking. For example, instead of iterators one could use Iterable or simply collections. Those offer natural ways of stubbing (e.g. using real collections). In rare scenarios stubbing consecutive calls could be useful, though:
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//First call: throws runtime exception:
mock.someMethod("some arg");
//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));
So in your case, you'd want:
when(myMock.doTheCall())
.thenReturn("You failed")
.thenReturn("Success");
The shortest way to write what you want is
when(myMock.doTheCall()).thenReturn("Success", "you failed");
When you supply mutiple arguments to thenReturn like this, each argument will be used at most once, except for the very last argument, which is used as many times as necessary. For example, in this case, if you make the call 4 times, you'll get "Success", "you failed", "you failed", "you failed".
Since the comment that relates to this is hard to read, I'll add a formatted answer.
If you are trying to do this with a void function that just throws an exception, followed by a no behavior step, then you would do something like this:
Mockito.doThrow(new Exception("MESSAGE"))
.doNothing()
.when(mockService).method(eq());
I have a different situation, I wanted to mock a void function for the first call and run it normally at the second call.
This works for me:
Mockito.doThrow(new RuntimeException("random runtime exception"))
.doCallRealMethod()
.when(spy).someMethod(Mockito.any());
To add on to this and this answer, you can also use a loop to chain the mocked calls. This is useful if you need to mock the same thing several times, or mock in some pattern.
Eg (albeit a farfetched one):
import org.mockito.stubbing.Stubber;
Stubber stubber = doThrow(new Exception("Exception!"));
for (int i=0; i<10; i++) {
if (i%2 == 0) {
stubber.doNothing();
} else {
stubber.doThrow(new Exception("Exception"));
}
}
stubber.when(myMockObject).someMethod(anyString());
The shortest would be
doReturn("Fail", "Success").when(myMock).doTheCall();