Junit- how to test invalid usage of parameters - java

I am supposed to write a Junit test for the invalid usage of correct parameters. I am a bit confused by this concept. Can someone please help to explain what is this scenario, and how to do this with an example?
I am testing a method that take a customer and a type of service as parameters. and I've tried the assertFalse method below, and tried to pass two customers to
assertFalse("Registration fails for add two services to one customer", cs.addPeople("Jack", "Jill","Cleaning"));
I realized that this is not the correct way as the add.People()method only takes one person as a parameter. In this case how can we test invalid usage? Many thanks!

By test invalid usage of parameters, I guess you mean write scenarios with invalid parameters.
For example.
Say that you have a method:
public Integer toInteger(String input){
//conversion logic
}
Now, you would want to know how your method behaves on different scenarios.
One scenario would be passing invalid parameter such as null, and see how your method behaves.
#Test
public void testToIntegerForNullParam(){
myClass.toInteger(null);
}
This method will not pass if you didn't handle null checking, and you will have to refactor to pass this test.
public Integer toInteger(String input){
if(input == null){
throw new IllegalArgumentException("Argument was null!");
}
//conversion logic
}
Then in your test, you can test if this indeed throws exception when argument is null. You can use expected = IllegalArgumentException.class
#Test(expected = IllegalArgumentException.class)
public void testToIntegerForNullParam(){
myClass.toInteger(null);
}
You can continue adding more scenarios such as string not being numeric etc.

Related

Mockito ArgumentCaptor needs stubbing even I use verify

I am trying to write a Unit Test for the following service method:
public CommandDTO update(UUID uuid, QuantityRequest request) {
Quantity quantity = quantityRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException(QUANTITY));
Quantity updated = saveQuantity(quantity, request);
return CommandDTO.builder().uuid(updated.getUuid()).build();
}
private Quantity saveQuantity(Quantity quantity, QuantityRequest request) {
//map fields (code omitted for brevity)
return quantityRepository.save(quantity);
}
I use ArgumentCaptor so that I catch the quantity parameter in the private method that my service method calls: quantityRepository.save(quantity).
#Test
public void test() {
Quantity quantity = new Quantity();
QuantityRequest request = new QuantityRequest();
request.setQuantity(100);
when(quantityRepository.findByUuid(uuid)).thenReturn(Optional.of(quantity));
// It seems to be meaningless this stubbing. because I already stb it in verify method below
when(quantityRepository.save(any())).thenReturn(quantity);
quantityService.update(uuid, request);
verify(quantityRepository).save(quantityCaptor.capture());
Quantity captured = quantityCaptor.getValue();
// assertions...
}
The test is working, but if I remove when(quantityRepository.save(any())).thenReturn(quantity); line, it throws "null pointer exception error" because in this case updated parameter in the update method is null. So, do I have to use the mentioned stubbing in the when() method? I think I do not need and the verify already perform that task via verify(quantityRepository).save(quantityCaptor.capture()). Is that true?
The problem lies in the following lines:
Quantity updated = saveQuantity(quantity, request);
return CommandDTO.builder().uuid(updated.getUuid()).build();
Which is essentially the same as:
Quantity updated = quantityRepository.save(quantity)
return CommandDTO.builder().uuid(updated.getUuid()).build();
The stubbing is necessary, because you're expecting the save method to return something, when you call updated.getUuid().
Without the stub, updated is null and your call results in a NullPointerException.
No, you need the stubbing here. You can't delete the when(save) call because your test depends on what return value you have for save. However, you're on the right track to question whether any given thing needs to be both stubbed and verified.
You're right that it's often redundant to verify things that you've stubbed, and the docs to verify tell you so:
Although it is possible to verify a stubbed invocation, usually it's just redundant. Let's say you've stubbed foo.bar(). If your code cares what foo.bar() returns then something else breaks(often before even verify() gets executed). If your code doesn't care what foo.bar() returns then it should not be stubbed.
And as attributed to Aaron Jensen, quoted in "Asking and Telling" by Mockito's original author Szczepan Faber:
If you’re verifying you don’t need to stub unless of course that method returns something that is critical to the flow of your test (or code), in which case you don’t really need to verify, because the flow would have verified.
In general, if you've stubbed something, then you make your test assertions at the end and you don't need to test that the method was called—the assertions would fail. And if you verify that a method was called but nobody cares about the result—or the result is passed directly back to the caller—then you might not need to stub, because Mockito's default return values like 0 and null should work fine.
Here, neither of those are true: A default null value causes an NPE, and you need to verify because that's the only supported way to get a value out of your ArgumentCaptor. This means that you call verify, but not for the sake of actual verification, but rather to get the value out of ArgumentCaptor. Part of the verify call is redundant, but there isn't another practical way to get to the necessary ArgumentCaptor part, so your code is fine with both when and verify.

Writing Unittest which takes 2 list

I am a new Junit Learner I would like to test my code according to 2 list class. However I never saw any example of that.
My real code is below :
public static List<JourneyType> applyFilter(List<JourneyType> journeyList, List<AvailabilityFilterOptionType> filterOptions)
{
List<JourneyType> filteredJourneyList = new ArrayList<>();
filteredJourneyList = applyStopFilters(journeyList, filterOptions);
filteredJourneyList = applyCarrierFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyRbdFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyDurationFilter(filteredJourneyList, filterOptions);
return filteredJourneyList;
}
and my test scenario :
#Test
public void testApplyFilter()
{
fail("Not yet implemented");
}
Thank you in advanced
Actually, this is pretty simple.
#Test
public void testApplyFilter()
{
assertThat(someObject.applyFilter(journies, filters), is(expectedOutcome));
}
In other words: you know what this method is supposed to do. ( Well, such knowledge is the prerequisite for testing stuff. When you don't know what your code is doing, there is no point in verifying its correctness via testing...)
As in: given some known input data, you should be able put down an expectation about output coming back. And that is what you check for.
Of course, the tricky part could be to correctly identify dependencies, and mock them where needed.
But ideally, your test should just be that: testing the public contract of your method under test. Something goes in, and you check that the output coming back meets your expectations. Ideally, you have to mock nothing for such tests, because you do not at all rely on testing implementation details. You only test the public contract "given this input, this is the expected output".
( where: assertThat() is just a different type of assert, and is() is a hamcrest matcher. There are many other hamcrest matchers, such as containsInAnyOrder() (that one is really neat if you don't care about the order of elements returned, but one has to understand that is used slightly different, it would need containsInAnyOrder(expectedOutcomeList.toArray()) methinks )

unittest - junit and Mockito. Test addNewAccount to Databases, f I need to remove/delete a account

I have written to Unit test - junit with Mockito library to test any methods, who save to databases new account - addNewAccount methods.
I would like to ask - if I need to add a method or what and how - to delete/remove an account, whos was added. and please show me what I can do it.
my unit test is:
#Test
public void shouldSaveaAccountToDb() {
Account acc = new Account();
acc.setUser(this.user);
acc.setEmail(this.mail);
String account = this.accountController.addNewAccount(this.user, this.mail);
verify(this.accountRepepetytory)).save(Mockito.refEq(acc, new String[0]));
Assert.assertThat(account, CoreMatchers.is("Account"));
}
I also want to add a case with a null value and testing null and empty string. if you can any idea to add test case please tell me.
thank you very match for help. I improved my test.
I have also a method who testing with null value. This is the method.
#Test
public void SaveToDatabaseWithNull() {
Account acc = new Account();
String mail = null;
user.setMail((String)mail);
user.setUser(this.user);
String account = this.accountController.addNewAccount(this.user, (String)mail);
verify(this.accountRepetytory)).save(Mockito.refEq(uaccount, new String[0]));
Assert.assertThataccountCoreMatchers.is("Account"));
}
I also would like to ask, whether in these tests it is necessary to delete some values, adding a method that deletes the account. if I create an account in one method, do I have to delete it in some way and in which way? to test correctly with the null value in the later method.
In your code you have some weaknesses that make you test britle and hard to understand:
Each test method should verify one single expectation only.
Your test verifies two things:
The code created an object of class Account that equals to the one created in the test method by the means of the Account classes implementation of equals().
The return value of the method is a string with content "Account".
Problem of that is that the test does not explain why you expect that string.
So basically you should have separate methods to verify either behavior allowing for a better description of the tested behavior in the test method name.
reduce dependencies to unrelated code.
Mockito.refEq() relies on a (correct) implementation of the equals method in class Account. There is no quaratee that this method is actually implemented or (even worse) may need addioional configuration in future if an account gets more properties that are not allowed to be null.
The better way here is to use an ArgumentCaptor and verify the properties of the captures object:
#Test
public void shouldPassAnAccountObjectWithNameAndEmailSetToDB() {
ArgumentCaptor<Account> accountCaptor =
ArgumentCaptor.forClass(
Account.class);
this.accountController.addNewAccount(
this.user,
this.mail);
verify(this.accountRepepetytory))
.save(
accountCaptor.capture());
Assert.assertThat(
"user",
accountCaptor.getValue().getUser(),
CoreMatchers.is(this.user));
Assert.assertThat(
"email",
accountCaptor.getValue().getEmail(),
CoreMatchers.is(this.email));
}

Assert statement for junit

My method returns null sometimes and not null values so how to write a assert for those scenarios
example:assertNotNull(some statement)
Simple:
#Test
public void testFooGivesNotNull() {
assertNotNull(foo.bar(somethingLeadingToNotNull));
}
#Test
public void testFooGivesNull() {
assertNull(foo.bar(somethingElseLeadingToNull));
}
In other words: you do that by identifying the possible test cases, to then write at least one test for each of the possible paths.
And for the record: returning null is rarely a good idea. That null is the first step towards running into a NullPointerException. Consider alternatives, such as
returning a special object that represents "null"
returning an Optional
throwing an exception
Just call your function and add an error message:
Assert.assertNotNull(someFunction(), "This should not be null");
A good way to use Assert.assertNotNull is via static import.
import static org.junit.Assert.assertNotNull;
assertNotNull(yourValueTobeCheckAsNull, "This should not be null");

What methods should I have JUnit tests for - How to mock methods with many dependencies

I am new to JUnit, and do not know which methods should have tests and which should not. Take the following example:
public List<Site> getSites(String user)
{
SiteDao dao = new SiteDaoImpl();
List<Site> siteList = new ArrayList<Site>();
ServiceRequest rq = new ServiceRequest();
rq.setUser(user);
try
{
ServiceResponse response = siteDAO.getReponse(rq);
List<String> siteNums = response.getSiteNums();
if (siteNums != null && !siteNums.isEmpty())
{
List<DbModelSite> siteInfo = dao.getSiteInfo(siteNums);
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = SiteMapper.mapSites(siteInfo);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return siteList;
}
public static List<Site> mapSites(List<DbModelSite> siteInfo)
{
List<Site> siteList = null;
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = new ArrayList<Site>();
for (DbModelSite temp : siteInfo)
{
Site currSite = mapSite(temp);
siteList.add(currSite);
}
}
return siteList;
}
public static Site mapSite(DbModelSite site)
{
Site mappedSite = null;
if (site != null)
{
mappedSite = new Site();
mappedSite.setSiteNum(site.getSiteNum());
mappedSite.setSpace(site.getSpace());
mappedSite.setIndicator("Y");
}
return mappedSite;
}
It is pretty trivial to come up with a unit test for both the mapSites() and mapSite()methods, but where I am having trouble is with the getSites() method. Does it make sense to unit test this method? If so, how would I go about doing so? It seems that this would require quite a bit of mocking, and as I am very new to JUnit, I have not been able to figure out how to mock all of these objects.
So my question is really two fold:
How do you determine if a method needs to be unit tested?
How does one unit test a complex method which requires a large amount of mocking?
Yes, it makes sense to test that method.
The first thing to be able to test it, would be to use dependency injection. If the method creates its own SiteDao instance using new, there is no way you can tell the method to use another, mock instance of SiteDao.
So, read on dependency injection, and use it. Basically, it boils down to
public class MyService {
private SiteDao siteDao;
public MyService(SiteDao siteDao) {
this.siteDao = siteDao;
}
// use the siteDao passed when constructing the object, instead of constructing it
}
That way, when testing your service, you can do
SiteDao mockSiteDao = mock(SiteDao.class);
SiteService service = new SiteService(mockSiteDao);
Here's one pice of advice that is not directly related to your question, but will make your code much simpler, and thus easier to test, too:
Never return null from a method returning a collection. Return an empty collection to signal "no element".
In general, don't accept null as a valid method argument value, especially if the argument is a collection.
Corollary of 1 and 2: by following these principles, you never need to check for null or emptyness of a collection. Just use it directly.
This will reduce the number of if (siteNums != null && !siteNums.isEmpty()) cluttering your code, and you'll have way fewer branches to test, too.
Note that all sane libraries (the JDK methods, JPA, etc.) follow these principles. A JPA query will never return a null list for example.
Also, don't swallow an exception by just printing its stack trace and returning an empty list, as if nothing bad happened. Let the exception propagate so that you can notice and fix the bug.
Just imagine that this method is a method returning the number of cancer tumors found by a medical analysis system. Would you really like the system to tell you that you're in perfect health, whereas the system was in fact unable to do its job due to an exception? I would really prefer the system to say "I'm out of order, use another machine to be sure".
The idea of unit testing is to ensure that each "unit" (which is usually a method) can be tested in isolation so you can test that for given input you receive an expected output, so to answer your questions:
I should say all public methods should be unit tested
If you are doing too much in your method that you need to mock lots then you probably want to break the functionality out into another class
Going back to your example there are a couple of things to be wary of if you want to unit test:
new - anytime you use this keyword in a method you will find it difficult to mock that object. In some cases (like ServiceRequest) it's fine but in others such as SiteDao you'll have problems.
Static methods - same thing, with SiteMapper.mapSites(siteInfo) you will find it difficult to mock
You can use libraries such as PowerMock to mock new, private and static methods but I personally try to avoid that.

Categories