Junit failed tests, how to fix this? - java

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")
}

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.

Simple Unit test with Mocks keeps failing; mock object not being passed to class?

I have a simple Unit Test that is failing. Hopefully I can explain this in simple terms as I've been looking at it for hours and I see what the issue is, but I am not too familiar the underlying theory behind Mocks so I am a bit confused and cannot fix it. I will summarize the issue very quickly and then paste the code below.
Basically, in my test method called getAllValidModelsTest(), it uses a for loop to iterate thru enum values of object type DeviceModel. There are only 5: [EX3400_24P, EX4300_32F, EX4300_48MP, SRX_345, FAUX].
So inside the for loop, before the Assert statement (Junit), it makes a static method call to getDevice(deviceId) and it should from there return a Device object. The first line under the for loop in the getAllValidModelsTest() mocks the elementMock object to return the current model that is being iterated over in the DeviceModels[] array that was returned from the .values() call on the enums DeviceModel class.
So my issue is, when it jumps in the 2nd iteration in my for loop (counting from 1), the Assert fails , because the 0th element in the DeviceModel[] array is obviously EX4300_32F, but in the #Before setUp annotation it is being mocked to return EX3400_24P. But the weird thing is, under the for loop inside the getAllValidModelsTest() method, it is being overridden/mocked again to return to the current model that is being iterated through when .getModel is called on the elementMock object, so it should be returning the SAME value...
This is how the class SwitchDeviceFactoryTest.java is constructed (the class with the Unit Test):
#PowerMockIgnore({"javax.net.ssl.*"})
#RunWith(PowerMockRunner.class)
#PrepareForTest({DataGatewayFactory.class, SwitchConfig.class, RouterConfig.class})
public class SwitchDeviceFactoryTest {
String deviceId = "testdevice";
String ip = "1.1.1.1";
DataGateway dbMock = Mockito.mock(DataGateway.class);
SwitchConfig swConfigMock = PowerMockito.mock(SwitchConfig.class);
RouterConfig routerConfigMock = PowerMockito.mock(RouterConfig.class);
TransportDeviceSecretsInfo secrets = new TransportDeviceSecretsInfo();
TransportDeviceSecretsData secretsData = new TransportDeviceSecretsData("root","rootPw", "sshUser", "sshPass", "snmpAuthPass", "snmpPrivPass");
IElement elementMock = Mockito.mock(IElement.class);
ITransportDeviceSecretsCrud transportDeviceSecretsCrud = mock(ITransportDeviceSecretsCrud.class);
ISwitchConfigCrud switchConfigCrud = mock(ISwitchConfigCrud.class);
IRouterConfigCrud routerConfigCrud = mock(IRouterConfigCrud.class);
IElementCrud elementCrud = mock(IElementCrud.class);
This is my setUp method that runs before the test. The only variables that should be of importance are the elementMock object, specifically the one being mocked to return the EX3400_24P object:
#Before
public void setup() throws Exception {
secrets.setSecretsData(secretsData);
PowerMockito.mockStatic(DataGatewayFactory.class);
Mockito.when(DataGatewayFactory.getInstance()).thenReturn(dbMock);
Mockito.when(dbMock.getTransportDeviceSecretsCrud()).thenReturn(transportDeviceSecretsCrud);
Mockito.when(transportDeviceSecretsCrud.getServerSecretsInfo(anyString())).thenReturn(Optional.of(secrets));
Mockito.when(transportDeviceSecretsCrud.getReportedSecretsInfo(anyString())).thenReturn(Optional.of(secrets));
when(dbMock.getElementCrud()).thenReturn(elementCrud);
doReturn(Optional.of(elementMock)).when(elementCrud).getById(anyString());
Mockito.when(elementMock.getModel()).thenReturn(DeviceModel.EX3400_24P.getModel());
Mockito.when(elementMock.getType()).thenReturn(ElementType.SWITCH);
Mockito.when(dbMock.getSwitchConfigCrud()).thenReturn(switchConfigCrud);
Mockito.when(switchConfigCrud.get(anyString())).thenReturn(Optional.of(swConfigMock));
Mockito.when(swConfigMock.getIp()).thenReturn(ip);
Mockito.when(dbMock.getRouterConfigCrud()).thenReturn(routerConfigCrud);
Mockito.when(routerConfigCrud.get(anyString())).thenReturn(Optional.of(routerConfigMock));
Mockito.when(routerConfigMock.getIp()).thenReturn(ip);
And the test method:
#Test
public void getAllValidModelsTest() throws Exception {
for (DeviceModel model: DeviceModel.values()) {
when(elementMock.getModel()).thenReturn(model.getModel());
if (model == DeviceModel.SRX_345)
when(elementMock.getType()).thenReturn(ElementType.ROUTER);
else
when(elementMock.getType()).thenReturn(ElementType.SWITCH);
Device device = DeviceFactory.getDevice(deviceId);
assertEquals(model, device.getModel());
}
}
The thing that doesn't make sense, is I was refactoring code, and only changed 2 lines (the elementCrud and elementMock .doReturn and .when calls) and it works perfectly fine on the develop branch.
When I debug, I can see that on the 2nd iteration of the for loop, .getModel returns EX3400_24P object inside the static getDevice method, when it should be returning model.getModel() , which would be the 2nd object being iterated on in the .values() enum array of DeviceModels... so it should be EX4300_32F.
On the develop branch, this works perfectly.... It's as if the Mockito mock object forgets what it's suppose to do when it jumps inside the DeviceFactory class inside the getDevice method once its called in my getAllValidModelsTest() method (i.e. Device device = DeviceFactory.getDevice(deviceId);)
Here is the .getDevice method from the DeviceFactory class:
public static Device getDevice(String serialNumber) throws Exception {
IElement element = dataGateway.getElementCrud().getById(serialNumber).get();
DeviceModel model = DeviceModel.valueOfLabel(element.getModel()); // right here is where it returns the wrong model... it returns EX3400_24P on the 2nd iteration
log.info("Found device {} in database", serialNumber);
if (serialNumber.startsWith(FakeDevicePrefix.ATGTEST.toString()) || serialNumber.startsWith(FakeDevicePrefix.FAKE.toString())) {
log.info("Detected FAKE/ATG serial number. Using FAUX device.");
model = DeviceModel.FAUX;
}
switch (element.getType()) {
case SWITCH:
SwitchConfig config = dataGateway.getSwitchConfigCrud().get(serialNumber).get();
return getDevice(serialNumber, config.getIp(), model);
case ROUTER:
RouterConfig rconfig = dataGateway.getRouterConfigCrud().get(serialNumber).get();
return getDevice(serialNumber, rconfig.getIp(), DeviceModel.SRX_345);
case PTP:
default:
log.warn("Unsupported device type {}", element.getType().toString());
throw new Exception("Unsupported device type " + element.getType().toString());
}
}
I did indeed comment out/remove the piece of code that mocks it to return EX3400_24P in the setUp() method with #Before annotation , but the tests fails with a NULL POINTER EXCEPTION at this point.
How does the .getModel method know to return what I mocked it to return in the previous class (SwitchDeviceFactoryTest.java) before it jumps into the DeviceFactory.java class? How does it remember that if I'm not passing it in as a variable into the getDevice() method?
Do I need to use PowerMock or something because this is a static method? How does this change anything?
Please help!

Mockito: No such instance method

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");

writing a junit test case for the calling of a method

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.

How do I test a very simple void method in jUnit?

I know there are several question about void-method Unit-Testing, but my question is different.
I'm learning java, so my boss give me some tasks with different requirements on my tasks.
In my actual task, there is a requirement which says, the jUnit test must cover >60%. So I need to test a very simple method to reach this 60%. The method is the following:
public void updateGreen() {
// delete this outprint if the Power Manager works
System.out.println(onCommand + "-green");
// p = Runtime.getRuntime().exec(command + "-green");
// wait until the command is finished
// p.waitFor();
}
Because of intern problems, I can't execute the command with the Runtime task. So there is only a System.out in this method.
I've multiple methods like that, so tests for this method will cover over 10% of my whole code.
Is it useful to test such a method? When yes, how?
If there is a lot of such methods, the thing which you might want to test here is that updateScreen() uses the right string, "some-command-green" and that the System.out is being invoked. In order to do this you might want to extract System.out into an object field and mock it (i.e. with Mockito's spy()) to test the string that was provided to println.
I.e.
class MyClass{
PrintStream out = System.out;
public void updateGreen() { ... }
}
In test:
#Test
public void testUpdate(){
MyClass myClass = new MyClass();
myClass.out = Mockito.spy(new PrintStream(...));
// mock a call with an expected input
doNothing().when(myClass.out).println("expected command");
myClass.updateGreen();
// test that there was a call
Mockito.verify(myClass.out, Mockito.times(1)).println("expected command");
}
You could return true if the method ran successfully and false otherwise. It would be easy to test for this.
You could also test the output of this method, as described here:
Should we unit test console outputs?
But in my experience, it is much better to have methods return an optimistic or pessimistic value (true/false, 1/0/-1 etc) to indicate their status.
You can also write a getter method for the onCommand flag:
public string getFlag(){
// some logic here
return "green";
// otherwise default to no flags
return "";
}
You could test that onCommand + "-green" has been written to System.out by using the System Rules library.

Categories

Resources