JUnit test another method that uses fail() - java

We have a rather complex object that is the result of calling our drools engine.
For JUnit testing our rules we create a RulesTestHelper class that offers a method "assertOurObject(OurObject expected, OurObject actual)" and does many assertions on the elements of OurObject (This might probably be solved better by writing our own Matcher but we aren't that far yet).
Now in our method "assertOurObject" the first check is done if any of the objects is null, like this:
if (expected == null || actual == null)
fail("Expected or actual is null");
Now I want to JUnit test this method and assert that when I set one of the two objects to "null" I will fail the test. So in other words, I expect the test to fail and this should be ok.
Is this possible and if so, how?

If you don't want to change your code, you can use a solution similar to what Anderson Vieira said but instead use
#Test(expected=AssertionError.class)
The junit fail() method throws an AssertionError that you can specifically expect

You could throw an exception when this case occurs and tell the test to expect it by annotating it with:
#Test(expected=NullPointerException.class)
public void testShouldFailIfAnyObjectIsNull() {
... // do something
if (expected == null || actual == null) {
throw new NullPointerException();
}
... // do something
}

Related

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.

Should I assert or throw an exception in a junit library?

I'm writting a java library to easily write some junit tests. I don't know if I must assert inside my library or throw an exception. Here is an example. Asuming I define, in my library, this function to check the number of methods of class
public void assertNumberOfMethods(Class clazz, int expectedNumberOfMethods) {
int numberOfMethods = clazz.getDeclaredMethods().length;
//TODO compare number and expected number
}
Should I
Directly assert inside my library
Assert.assertTrue(expectedNumberofMethod > 0);
Assert.assertEquals(numberOfMethods,expectedNumberOfMethods);
//...
Throw an exception an let the user handle this exception. Since this library is designed to be used in unit tests, the user will be able to catch some of this exception using #Test(expected=SomeCustomException.class)
public void assertNumberOfMethods(Class clazz, int expectedNumberOfMethods) throws IllegalArgumentException, SomeCustomException {
if(expectedNumberOfMethods <= 0)
throw new IllegalArgumentException(/*...*/);
int numberOfMethods = clazz.getDeclaredMethods().length;
if(numberOfMethods != expectedNumberOfMethods)
throw new SomeCustomException(/*...*/);
}
EDIT This is a dummy example
Your are planning to create specialized assert methods, like as you would write an extension to the Assert class.
For this you should directly throw assert errors (variant 1), as the assert methods in Assertdo, providing a helpful error message.
The possibility to specify expected exceptions in the #Test annotation serves a different purpose. With this annotation Junit allows you to test that a piece of code throws an expected exception, without the need in the test code to catch the exception.
I would use the junit fail() method that is used in pretty much all other assert methods in the junit library
public void assertNumberOfMethods(Class clazz, int expectedNumberOfMethods) {
int numberOfMethods = clazz.getDeclaredMethods().length;
if (numberOfMethods != expectedNumberOfMethods) {
fail("some failing message);
}
}
You should throw a java.lang.AssertionError exception if an assertion is false.
Also, try not to re-invent the wheel, take a look at AssertJ which does exactly what you want.
// Example
assertThat(clazz.getDeclaredMethods()).hasSize(5);
expectedNumberofMethod > 0 should be an IllegalArgumentException. The test has not failed, the method has been called incorrectly.
numberOfMethods == expectedNumberOfMethods should throw a java.lang.AssertionError (or a like), how you do this is up to you, you could use Assert.assertThat, but it binds you to a test framework. You could throw it directly, but you have to do more manual work.
If you use Assert.assertThat, remember that the first argument can be a String description of what went wrong. Use it.
Don't use custom exceptions (that do not extent java.lang.AssertionError), think about what the users of your API will be expecting, and do that. Every other assert causes a java.lang.AssertionError to be throw, but you are doing something different.

Junit- how to test invalid usage of parameters

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.

Test that void method didn't get called with EasyMock

Is this possible?
I tried with EasyMock.expectLastCall().times(0); but EasyMock complains that times must be >=1
You could use .andThrow(new AssertionFailedError()).anyTimes(); - this is the same exception that Assert.fail() throws, but is less verbose than making an Answer.
with easymock 3.0, you need to add a .anyTimes() on the expectLastCall or the test will fail:
Expectation failure on verify: myMethod(): expected: 1, actual: 0`
based on nkr1pt example:
expectLastCall().andAnswer(new IAnswer() {
public Object answer() {
Assert.assertFail();
return null;
}
}).anyTimes();
The fact that some method is not called is controlled by Mock or StrictMock. They will throw an exception, when that not recorded method is called. This problem occurs only when using NiceMocks, where default values are returned when calling for not recorded methods.
So a solution can be not to use NiceMocks.
Looks like a bug to me. The internal class Range does not allow to set a maximum less than 1.
Couldn't you mock that method, and just call Assert.fail() ?
If you expect your method not to be called then just don't record it. But I agree it won't work with a nice mock.
I managed to come up with a solution:
expectLastCall().andAnswer(new IAnswer() {
public Object answer() {
Assert.assertFail();
return null;
}
});

Categories