I am newbie to unit testing. I am using TestNG with MyEclipse to develop unit test cases for my application. While doing it I am facing some problems with EasyMock. Here is my code (Name of the class, method names and return types are changed for security reasons but you will get a clear idea what I am trying to achieve here).
public MyClass
{
// This is a method in my class which calls a collaborator which I
// want to mock in my test case
public SomeObject findSomething(SomeOtherObject param) throws Exception
{
SomeOtherObject param a = myCollaborator.doSomething(param);
// Do something with the object and then return it
return a;
}
}
Now here is my test. Now what I actually want to achieve in my test
case is that I want to check that my function (findSomething) properly
throws exception in case some exception is thrown. In future some
other developer can change the signature (throws Exception isn't
really part of method signature) of the method and remove the throws
Exception from my method. So how can I make sure that nobody changes
it?
#Test(dataProvider="mydataProvider", expectedExceptions=Exception.class)
public void MyTest(SomeOtherObject param) throws Exception {
{
EasyMock.expect(myCollaboratorMock.doSomething(param)).andThrow(new Exception());
EasyMock.replay(myCollaboratorMock);
}
I am getting exception
"java.lang.IllegalArgumentException: last
method called on mock cannot throw java.lang.Exception"
What I am
doing wrong here? Can someone shed some light on how to write a test
case for my particular scenario?
The collaborator's doSomething() method doesn't declare that it may throw Exception, and you're telling its mock to throw one. It's not possible.
Exception is a checked exception. It can only be thrown if it's declared in the method signature. If the method has no throws clause, all it can do is throwing runtime exceptions (i.e. RuntimeException or any descendant class).
Related
I have method that throws an exception in special circumstances. I would like to write a test case that will check behaviour when exception is not thrown.
I cannot find this in docs or examples. Please help.
E.g.:
when(validator.validate(any(ValidationData.class))).thenThrow(new ValidationException());
But I would like to test that exception is not thrown at all:
class Validator {
void validate(ValidationData dataToValidate) throws Exception {
}
}
e.g. I need something like:
when(doSomething()).thenNotThrowException
or
when(doSomething()).thenDoNothing
By default, Mockito's mock does nothing for void methods, so you don't need to write anything.
If you want to do this explicitly try this:
doNothing().when( validator ).validate( any() );
To test the case where no exceptions is thrown, you actually need to do even less:
Do not program the thenThrow at all
In your test case, expect the test method to run normally and complete without exceptions (in Junit, don't have any expected attribute for #Test)
If the test is executed without errors, then your test passed.
If you just want to test that there are no exceptions in a test function, you should use this annotation: #Test(expected = Test.None.class)
Example:
#Test(expected = Test.None.class)
public void testFunction() {
// some code
}
I have inherited some code from another team which uses
#Test (expectedExceptions = {Exception.class})
everywhere when the code might be throwing a more specific exception.
My understanding is that this is wrong because we are not expecting the right type of exception. But the current owners are saying that they have seen no issue because of this.
Is my understanding correct?
This is poor design, since it could be masking errors other than the one being tested for. As an example, suppose your code should throw a SecurityException on some operation but instead is throwing a NullPointerException because of a naive dereference. Your test would pass when it should fail.
You should always make your matchers as specific as possible, and in this case, that means the most specific exception class that applies.
Exception is Parent class of all types of exception in java, so basically your test will pass if code throws any checked or unchecked exception. But its better to write unit test that will expect a particular type of exception which your code can throw. For e.g. let say your have a method to validateParam
public void validateParam(String param) throws SomeCustomValidationException {
//suppose param is null , now this code will throw NullPointerException
if (param.length() > 2) {throw new SomeCustomValidationException();}
}
and you call it like this
public void businessLogic(String param) {
try {validateParam(param);}
catch(SomeCustomValidationException e){//show error dialog to the user}
}
So although your unit test will pass but your business logic will not work as you expected
If I write test cases for a function that throws a bunch of exceptions should I add a throws declaration for these exceptions in my test method or should I catch each individual exception. What is the correct way of going about it? I believe try-catch is a better way but in the catch block should I print the stacktrace?
For example, I have a method getGroups(String name) that throws AuthenticationException. If I write a test case to check if an IllegalArgumentException is being thrown when the name parameter is null, how do I handle the AuthenticationException? Do I add it to throws part of my method or should I enclose the exception in a try-catch block.
#Test
public void testGetGroupsWithNull() throws AuthenticationException {
thrown.expect(IllegalArgumentException.class);
getGroups(null);
}
In the above test case I just added a throws AuthenticationException, but I would like to know if it is better to enclose the exception in a try-catch block and what shoudld I do after catching the exception. I could print the stack trace.
I am handling the unexpected exception AuthenticationExceptionby not placing it in the 'throws' clause but in a try/catch block.
#Test
public void testGetGroupsWithNull() {
thrown.expect(IllegalArgumentException.class);
try {
getGroups(null);
} catch(AuthenticationExcption e) {
Assert.fail("Authentication Exception");
}
}
JUnit has a great article here: https://github.com/junit-team/junit/wiki/Exception-testing on this very subject.
You can do:
#Test(expected= IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
or:
#Test
public void testExceptionMessage() {
try {
new ArrayList<Object>().get(0);
fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
}
}
If a JUnit test throws an unexpected exception, it fails. That is the behaviour that you want. So there's no point in EVER using a try/catch block. If you're expecting an exception, use an ExpectedException rule (which you obviously know about, from your code snippet). But whether you're expecting one or not, don't use try/catch.
This means that if your exception is a checked exception, you need a throws clause. In fact, you'll often need a throws clause on your test method, even when you're NOT expecting the exception to be thrown, just because your test calls a method that can SOMETIMES throw a checked exception. I have got into the habit of writing throws Exception on every single test method. There is no reason not to; and it's just one less thing to worry about.
The annotation is more communicative.
It signals what the test expects to happen without forcing the reader to read the code.
Any single test should only expect a single exception to be thrown, because each test should be testing a single behavior. A single behavior can only throw one exception.
If any other exception is thrown it's a test failure. The test method signature must reflect any possible checked exceptions, of course, as would real code calling that same method.
Using the rule of writing as little code as possible to solve the problem, your first code snippet wins. So yes, put the AuthenticationException into your test method's throws clause. It is more succinct and readable.
I've just looking for the same question since I'm dealing with your topic and I found a good explanation for unit test best practices. A little extraction from the article can help you.
It is unnecessary to write your own catch blocks that exist only to fail a test because the JUnit framework takes care of the situation for you. For example, suppose you are writing unit tests for the following method:
final class Foo {
int foo(int i) throws IOException;
}
Here we have a method that accepts an integer and returns an integer and throws an IOException if it encounters an error. Here is the wrong way to write a unit test that confirms that the method returns three when passed seven:
// Don't do this - it's not necessary to write the try/catch!
#Test
public void foo_seven()
{
try
{
assertEquals(3, new Foo().foo(7));
}
catch (final IOException e)
{
fail();
}
}
The method under test specifies that it can throw IOException, which is a checked exception. Therefore, the unit test won't compile unless you catch the exception or declare that the test method can propagate the exception. The second alternative is preferred because it results in shorter and more focused tests:
// Do this instead
#Test
public void foo_seven() throws Exception
{
assertEquals(3, new Foo().foo(7));
}
We declare that the test method throws Exception rather than throws IOException. The JUnit framework will make sure that this test fails if any exception occurs during the invocation of the method under test - there's no need to write your own exception handling.
You can find more about JUnit best practices like above in this article:
http://www.kyleblaney.com/junit-best-practices/
Hope to help.
I came across a problem and I can't find an elegant solution.
So the problem is with a mock of Selenium web driver, and I dont know how should I test/mock void methods.
public void clickAndWait(String locator) {
if(isElementPresent(locator) == false) throw some exception;
selenium.clickAndWait(); //a problematic delegating call to selenium
}
So what I am asking is, how to properly test such a method, one test would be for exception being thrown, but how properly make test of that void method I delegate to?
The following code sample from this Mockito documentation illustrates how to mock a void method:
doThrow(new RuntimeException()).when(mockedList).clear();
// following throws RuntimeException:
mockedList.clear();
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
return null;
}
}).when(mock).method((SomeClass) anyObject());
The previous answers have been stressing on doing something (throwing an exception possibly) at every call. This way when you do something like :
doThrow(new RuntimeException()).when(mockedList).clear();
and then call the stubbed service (or logic) like :
mockedList.clear();
it will generate an exception. What if you want to test for a proper functioning of method maybe writing positive test case. Mocking a void returning method for such case could be done by :
doNothing().when(mockedList).clear();
which means that since you stubbed the clear() method for mockedList mock, you can be sure that this method is not going to effect the logic of the unit and still you can check the rest of the flow without generating an exception.
You can also use:
The method Mockito.verify(mock/spy) to check how many times the method has been called.
Or use the argument captor to see/check some parameters passed to the void method.
You can trow an exception on your method call, here is a small example how to do it:
doThrow(new RuntimeException()).when(mockedList).clear();
then you call mockedList.clear(); mocked method will throw an exception.
Or you can count how many times your method was called, here is a small example how to do it:
verify(mockedList, times(1)).clear();
In Java 8 this can be made a little cleaner
doAnswer((i) -> {
// Do stuff with i.getArguments() here
return null;
}).when(*mock*).*method*(*methodArguments*);
The return null; is important and without it the compile will fail with some fairly obscure errors as it won't be able to find a suitable override for doAnswer.
My Test: this is where it underlines the stuff after sax. and insists that I have a try-catch block.... but the internet says that the proper way to test for exception is #Test(expected=IllegalArgumentException.class)
#Test(expected= XMLClientNotFoind.class)
public void testGetClientFromIP() throws XMLClientNotFound{
...
assertEquals(c, sax.getClientFromIP("101.0.2.01"));
}
And the method, getClientFromIP is here:
public Client getClientFromIP(String ip) throws XMLClientNotFound {
...
throw new XMLClientNotFound();
}
And my exception:
public class XMLClientNotFound extends Exception{
}
First of all:
#Test(expected=IllegalArgumentException.class)
should not be considered as a proper way, especially with such a generic exception. The reason is that you have no control over which statement in your test method actually threw the exception. Also you can't make any assertions on the message label, cause, etc.
Using try-catch precisely surrounding a line that is suppose to throw an exception is the right way to go:
try {
shouldThrow()
fail("Expected exception");
} catch(XMLClientNotFound e) {
assertThat(e).hasMessage("Expected message"); //FEST-Assert syntax
}
You might also try JUnit #Rule that I wrote some time ago to make your test more readable.
You still need to define throws clause for checked exceptions. #Test(expected=...) part just says JUnit that you expect your test case to throw that exception(s).
Is it possible you have other code in the test method that throws a different exception?
For example...
#Test(expected= XMLClientNotFoind.class)
public void testGetClientFromIP() throws XMLClientNotFound{
thisMethodThrows_ExceptionX();
assertEquals(c, sax.getClientFromIP("101.0.2.01"));
}
In the above case the compiler would complain because you are not handling ExceptionX. You would either have to surround with try/catch or say throws ExceptionX in test method signature as well.
In general it is a good idea to test one thing in a test method. I do not understand the assertion if you are expecting the method to throw an exception; there is nothing to assert since it is not going to return anything.