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

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.

Related

Throwing Exception out of annotation

I have an annotation on a method M in which I am making some checks, if the checks doesn't succeed I do not want to execute the underlying method M. I want the caller to know that the call didn't succeed along with the reason.
To achieve this I am throwing an exception out of annotation if checks fails. So here I have a couple of questions:
I am unable to catch the specific exception because the IDE tells me that exception is not being thrown out of the method?
For a quick hack I am catching Exception and then get to the specific Exception by using instance of operator.
Is there any other better way to achieve this?
Do I have a way in which I need not throw the exception?
Annotation aspect code looks something like this:
#Before(value = "#annotation(abc)", argNames = "pjp, abc")
public Object around(ProceedingJoinPoint pjp, ABC abc) throws Throwable {
if(notAllow()){
throw new CustomException("Not allowed");
} else {
pjp.proceed()
}
}
}
The handler code looks something like this:
catch(Exception e){
if(e instanceof CustomException){
// do something
}
}
The IDE can only verify checked exceptions. Make the exception extend RuntimeException.
You can catch that any time you want, because the IDE cannot verify if any code throws it, since methods are not required to declare if they do.

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.

JUnit test another method that uses fail()

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
}

Java: proper design for multierror functionality

I am writing piece of code in Java, which job is to parse configuration file. It's convenient for the end-users, because they can see and fix all parsing errors at once. But it's not very good for testing - instead of specific exceptions test function just expects very general ParsingError exception.
It's always a room for dark magic here, like testing private methods, but I don't want to go for it. Could you suggest better design solution for the case?
Why not throw just a single InvalidConfigurationException (I wouldn't use ParsingError - aside from anything else, I wouldn't expect this to be an Error subclass) which contains information about the specific problems? That information wouldn't be in terms of exceptions, but just "normal" data classes indicating (say) the line number and type of error.
Your tests would then catch the exception, and validate the contents was as expected.
The implementation would probably start off with an empty list of errors, and accumulate them - then if the list is non-empty at the end of the parsing code, throw an exception which is provided with that list of errors.
I have been here before. Exceptions are unsuitable. Instead you should provide a report inside your parser.
parser.parse();
if (parser.hasErrors()) {
for (ParserError error : parser.getErrors()) {
// Provide a report to the user somehow
}
}
Simple and easy to read. An exception should be thrown if there is an exception condition - e.g. there is no source data to parse, not because the parser found problems.
Why not use chained exceptions? You could build specific exceptions (say ParticularParsingError), then chain this with ParsingError and throw that back.
In your unit tests, use e.getCause() where e is a ParsingError.
First things first: ParsingError seems a strange name, ParsingException looks better (Error is a java.lang class that should not be caught)
You could add a list in your ParsingException and add a try-catch block in your test in which you test that your list contains what you expect.
For example you had:
#Test(expected=ParsingException.class)
public void test_myMethod_myTestCase(){
myMethod()
}
but then you would have:
public void test_myMethod_myTestCase(){
try {
myMethod()
}
catch(ParsingException pe) {
if (! pe.list.contains(anError)
|| ! pe.list.contains(anOtherError) ) {
fail();
}
}
}

JUnit4 #Test(expected=MyException.class) VS try/catch

I'm pondering on exception handling and unit tests best practices because we're trying to get some code best practices in place.
A previous article regarding best practices, found on our company wiki, stated "Do not use try/catch, but use Junit4 #Test(expect=MyException.class)", without further information. I'm not convinced.
Many of our custom exception have an Enum in order to identify the failure cause.
As a result, I would rather see a test like :
#Test
public void testDoSomethingFailsBecauseZzz() {
try{
doSomething();
} catch(OurCustomException e){
assertEquals("Omg it failed, but not like we planned", FailureEnum.ZZZ, e.getFailure());
}
}
than :
#Test(expected = OurCustomException.class)
public void testDoSomethingFailsBecauseZzz() {
doSomething();
}
when doSomethig() looks like :
public void doSomething throws OurCustomException {
if(Aaa) {
throw OurCustomException(FailureEnum.AAA);
}
if(Zzz) {
throw OurCustomException(FailureEnum.ZZZ);
}
// ...
}
On a side note, I am more than convinced that on some cases #Test(expected=blabla.class) IS the best choice (for example when the exception is precise and there can be no doubt about what's causing it).
Am I missing something here or should I push the use of try/catch when necessary ?
It sounds like your enum is being used as an alternative to an exception hierarchy? Perhaps if you had an exception hierarchy the #Test(expected=XYZ.class) would become more useful?
If you simply want to check that an exception of a certain type was thrown, use the annotation's expected property.
If you want to check properties of the thrown exception (e.g. the message, or a custom member value), catch it in the test and make assertions.
In your case, it seems like you want the latter (to assert that the exception has a certain FailureEnum value); there's nothing wrong with using the try/catch.
The generalization that you should "not use try/catch" (interpreted as "never") is bunk.
Jeff is right though; the organization of your exception hierarchy is suspect. However, you seem to recognize this. :)
If you want to check the raw exception type, then the expected method is appropriate. Otherwise, if you need to test something about the exception (and regardless of the enum weirdness testing the message content is common) you can do the try catch, but that is a bit old-school. The new JUnit way to do it is with a MethodRule. The one that comes in the API (ExpectedException) is about testing the message specifically, but you can easily look at the code and adapt that implementation to check for failure enums.
In your special case, you want to test (1) if the expected exception type is thrown and (2) if the error number is correct, because the method can thrown the same exception with different types.
This requires an inspection of the exception object. But, you can stick to the recommendation and verify that the right exception has been thrown:
#Test(expected = OurCustomException.class)
public void testDoSomethingFailsBecauseZzz() {
try {
doSomething();
} catch (OurCustomException e) {
if (e.getFailureEnum.equals(FailureEnum.ZZZ)) // use *your* method here
throw e;
fail("Catched OurCostomException with unexpected failure number: "
+ e.getFailureEnum().getValue()); // again: your enum method here
}
}
This pattern will eat the unexpected exception and make the test fail.
Edit
Changed it because I missed the obvious: we can make a test case fail and capture a message. So now: the test passes, if the expected exception with the expected error code is thrown. If the test fails because we got an unexpected error, then we can read the error code.
I came across this when searching how to handle exceptions.
As #Yishai mentioned, the preferred way to expect exceptions is using JUnit rules and ExpectedException.
When using #Test(expected=SomeException.class) a test method will pass if the exception is thrown anywhere in the method.
When you use ExpectedException:
#Test
public void testException()
{
// If SomeException is thrown here, the test will fail.
expectedException.expect(SomeException.class);
// If SomeException is thrown here, the test will pass.
}
You can also test:
an expected message: ExpectedException.expectMessage();
an expected cause: expectedException.expectCause().
As a side note: I don't think using enums for exception messages/causes is good practice. (Please correct me if I'm wrong.)
I made catch-exception because I was facing the same problem as you did, Stph.
With catch-exception your code could look like this:
#Test
public void testDoSomethingFailsBecauseZzz() {
verifyException(myObj, OurCustomException.class).doSomething();
assertEquals("Omg it failed, but not like we planned", FailureEnum.ZZZ,
((OurCustomException)caughtException()).getFailure() ;
}

Categories