How do you customize exception handling behavior in JUnit 3? - java

I want to implement exception checking (like in JUnit 4) using JUnit 3. For example, I would like to be able to write tests like this:
public void testMyExceptionThrown() throws Exception {
shouldThrow(MyException.class);
doSomethingThatMightThrowMyException();
}
This should succeed if and only if a MyException is thrown.
There is the ExceptionTestCase class in JUnit, but but I want something that each test* method can decide to use or not use. What is the best way to achieve this?

Would the solution:
public void testMyExceptionThrown() throws Exception {
try {
doSomethingThatMightThrowMyException();
fail("Expected Exception MyException");
} catch(MyException e) {
// do nothing, it's OK
}
}
be suitable for what you're thinking of?
Also have a look at this thread, where someone created a Proxy-solution for JUnit3 which seems to be another possibility to solve your problem.

There is no need to implement your own solution because there is already one that can be used with JUnit3 (and any other testing framework): catch-exception.

The simplest approach is to use the Execute Around idiom to abstract away the try-catch that you would usually write.
More sophisticated is to note that TestCase is just a Test. I forget the details, but we can override the execution of the test (which the framework initially calls through run(TestResult) specified in Test). In that override we can place the try-catch, as per Execute Around. The testXxx method should call a set method to install the expected exception type.

Related

Java (JUnit 4.xx) How to force call an exception in the try block with a void method using mocking tools?

Here is a snippet of my code. I want to force call the catch block with WakeupException.
public void run() {
try {
try {
while (true) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "Attempting to Poll");
ConsumerRecords<String, String> records = consumer.poll(10000);
if (records.count() == 0) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "No Response. Invalid Topic");
break;
}
else if(records.count()>0) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "Response Received");
}
}
}
} catch (WakeupException e) {
consumer.close();
}
}
Here is what I tried:
#Test(expected = WakeupException.class)
public void failRun() throws WakeupException, IOException {
KafkaConsumerForTests consumerThread3;
consumerThread3 = Mockito.mock(KafkaConsumerForTests.class);
doThrow(new WakeupException()).when(consumerThread3).run();
//Mockito.when(consumerThread2.run()).thenThrow(new WakeupException());
consumerThread3.run();
}
I just want to call the WakeupException so that I get line coverage for that block of code. What would I do. This is a void method by the way. I'm open to suggestions involving PowerMock as well.
After seeing the code, I am quite sure that the call we want to mock is consumer.poll(...). I am not an expert in using Kafka so take everything from here with a grain of salt. Seeing that consumer is an attribute of the class under test, it should be possible to inject a mocked instance into the class under test and throw the WakeupException we need. Instead of (or additional to - your decision) the class under test, we create a(n additional) mock of the consumer and mock its poll(...)-method to throw the desired WakeupException when called. Instead of mocking the call to consumerThread3.run(), we mock the call to consumer.poll(...).
A remark on your question: "I just want to call the WakeupException so that I get line coverage" - This should never be the reason to write a test. A test should test behaviour. If there is no behaviour to test (which is rarely the case), do not write a test.
OP edited the question and added some additional information. I am quite confident that the first paragraph of this post should answer the question. The other paragraphs were written before OP added the relevant code in the try-block. They are written on a more abstract level. The interested reader may read them, but this is not necessary to understand the answer.
お楽しみください! - Please enjoy!
We want to verify the behaviour of the catch-block. In productive code, something in the try-block would throw the corresponding Exception triggering the catch-block. Thus, in order to test the catch-block, we should mock something in the try-block to throw said Exception.
If mocking a call within the block seems impossible, that may be due to the fact that the code was not developed test-driven. You see, an upside of Test-Driven Development is that you intrinsically generate testable code. If we are stuck with untestable/hard to test code, w ehave two (or maybe three) options:
Leave it as is, do not test it. This can be a valid answer if there is no behaviour to test.
Rewrite the code, make it testable. Depending on the structure of your project this could take from five minutes up to 2 weeks or more. Hard to say without knowing the codebase
Use unconventional tools. Normal mocking frameworks like Mockito have certain limittations, e.g. for Mockito mocking of static or final methods is not supported. Other tools, like PowerMock, aim to eliminate those limitations. But be warned: PowerMock operates on bytecode level. This means that
we are not necessarily testing the bytecode we use in production
this can screw with other tools, e.g. JaCoCo.
Those tools should be your last resort only and used sparsely.

EasyMock test an exception is thrown in the middle of code

I am writing test using EasyMock and there is a piece of source code like this:
public void doSomething(){
try
{
// Do something
}
catch (RejectedExecutionException ex)
{
// just add some metrics here, no big action
}
}
i am writing test for the case throwing RejectedExecutionException, but exception is not thrown finally, which means i can't use ExpectedException. So how should i test this exception is thrown once with EasyMock?
I do not think that you have a clean way to do this with any mockup framework. I however can suggest you the following solutions.
Solution 1
Modify you code of doSomething() as following:
public void doSomething(){
try
{
doSomethingImpl(); // throws RejectedExecutionException
}
catch (RejectedExecutionException ex)
{
// just add some metrics here, no big action
}
}.
Now implement test for both doSomethingImpl() that should throw exception and doSomething() that should not with the same input data and state.
Solution 2
You catch code does something, doesn't it? For example calls log.error(). You can verify that specific call indeed happened and happened only once. I do not remember the specific syntax to do this with EasyMock, but with Mockito it is very simple: use Mockito.verify().
Solution 3
You can use PowerMock to check that constructor of you exception was called. It is not very clean because theoretically you can create instance of exception but do not throw it, but it is better than nothing.
Probably you can even combine these solutions. However I believe that the first is the best one.
The Do something part calls a mock throwing the exception?
If yes, just do expect(mock.methodCalled()).andThrow(new RejectedExecutionException());
And then EasyMock.verify(mock) at the end of your test. This will make sure methodCalled was called once and only once.

How to capture all uncaucht exceptions on junit tests?

If we have created a singleton object to handle an Java Exceptions, why Thread.setDefaultUncaughtExceptionHandler runs ok in Java Application Server, Java Console Application but not works on JUnit tests?
For example, the following code works:
public class Main extends Object {
public static void main(String[] arguments) {
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler.getInstance());
double a = 1/0;
}
}
but this JUnit test not:
public class UncaughtExceptionHandlerTest {
#Test
public void throwException() {
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler.getInstance());
double a = 1/0;
}
}
but why? And, how can we solve this, to automatically handle all JUnit test exceptions without using a moody try catch to each test?
The JUnit will be catching all unexpected exceptions that are thrown by the unit tests on the unit test threads1. The normal behavior is to catch / display / record the exception as a FAILed test, and then continue with the next unit test.
This means that the there is no "uncaught exception" in the Java sense, and your uncaught exception handler is not going to be called.
It is not entirely clear what you are trying to achieve here, but I suspect that the answer would be to implement a custom runner:
https://github.com/junit-team/junit4/wiki/Test-runners
1 - If the code under test spawns its own threads, the JUnit framework has no way of knowing. It certainly cannot catch / detect uncaught exceptions on those threads. However, this doesn't seem to be what you are talking about in this question.
The main motivation, is, for example, send an e-mail or perform another administrative tasks if a junit test fail. If I have a global exception handler I could do this, instead put a catch block to each test. After the handling, maybe I will throw this exception and let junit go ahead as it does.
Well if that is what you are trying to do, then you are (IMO) doing it the wrong way. There are existing runners that provide a structured report file, or a report data structure that can give you a list of all tests that passed, failed from an assertion, failed from an exception, etc. What you should do is:
choose an appropriate runner
analyse its output
send a single email (or whatever) if there are errors that meet your criteria.
Advantages:
less effort
you deal with all errors not just uncaught exceptions (though actually assertion failures manifest as AssertionError exceptions ...)
you don't spam yourself on each and every failed test.
And there's another way. Look at JUnitCore (link). This allows you register a listener for the various test events, and then run a bunch of tests or test suites.
The other point is that you appear to be trying to duplicate (some of) the functionality of a Continuous Integration (CI) server such as Jenkins.
You then asked why this doesn't work:
#Test
public void throwException() {
Thread.setDefaultUncaughtExceptionHandler(/* some handler */));
double a = 1/0;
}
An uncaught exception handler is only invoked if nothing else catches the exception. But a typical JUnit test runner catches all exceptions that propagate from each unit test using a conventional exception handler. That means that the ArithmeticException thrown in your test never reaches your handler.
Exceptions thrown by your junit #Test method are not uncaught. JUnit catches them and uses them to fail your tests.
Now, if you had started a new Thread of your own that is not running inside JUnit's try/catch execution, a thrown exception will be essentially ignored and your test will pass.
Just think of the name... Thread.setDefaultUncaughtExceptionHandler. This only covers threads that do not explicitly have an uncaught exception handler, and then it doesn't cover exceptions that are caught by the code calling your code (JUnit, etc).
Here is relevant code from ParentRunner class:
protected final void runLeaf(Statement statement,
Description description, RunNotifier notifier) {
EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
eachNotifier.fireTestStarted();
try {
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
}
Are you sure that jUnit isn't catching it somewhere? The method signature says that it throws Exception so I'd guess that there has to be a pretty broad catch statement up-stream.

How to mock/test method that returns void, possibly in Mockito

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.

JUnit4 fail() is here, but where is pass()?

There is a fail() method in JUnit4 library. I like it, but experiencing a lack of pass() method which is not present in the library. Why is it so?
I've found out that I can use assertTrue(true) instead but still looks unlogical.
#Test
public void testSetterForeignWord(){
try {
card.setForeignWord("");
fail();
} catch (IncorrectArgumentForSetter ex){
}
// assertTrue(true);
}
Call return statement anytime your test is finished and passed.
As long as the test doesn't throw an exception, it passes, unless your #Test annotation specifies an expected exception. I suppose a pass() could throw a special exception that JUnit always interprets as passing, so as to short circuit the test, but that would go against the usual design of tests (i.e. assume success and only fail if an assertion fails) and, if people got the idea that it was preferable to use pass(), it would significantly slow down a large suite of passing tests (due to the overhead of exception creation). Failing tests should not be the norm, so it's not a big deal if they have that overhead.
Note that your example could be rewritten like this:
#Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
card.setForeignWord("");
}
Also, you should favor the use of standard Java exceptions. Your IncorrectArgumentForSetter should probably be an IllegalArgumentException.
I think this question needs an updated answer, since most of the answers here are fairly outdated.
Firstly to the OP's question:
I think its pretty well accepted that introducing the "expected excepetion" concept into JUnit was a bad move, since that exception could be raised anywhere, and it will pass the test. It works if your throwing (and asserting on) very domain specific exceptions, but I only throw those kinds of exceptions when I'm working on code that needs to be absolutely immaculate, --most APIS will simply throw the built in exceptions like IllegalArgumentException or IllegalStateException. If two calls your making could potentitally throw these exceptions, then the #ExpectedException annotation will green-bar your test even if its the wrong line that throws the exception!
For this situation I've written a class that I'm sure many others here have written, that's an assertThrows method:
public class Exceptions {
private Exceptions(){}
public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
try{
actionThatShouldThrow.run();
fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
}
catch(Exception e){
if ( ! expectedException.isInstance(e)) {
throw e;
}
}
}
}
this method simply returns if the exception is thrown, allowing you to do further assertions/verification in your test.
with java 8 syntax your test looks really nice. Below is one of the simpler tests on our model that uses the method:
#Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
//setup
AxisRange range = new AxisRange(0,100);
//act
Runnable act = () -> range.setLowerBound(200);
//assert
assertThrows(IllegalArgumentException.class, act);
}
these tests are a little wonky because the "act" step doesn't actually perform any action, but I think the meaning is still fairly clear.
there's also a tiny little library on maven called catch-exception that uses the mockito-style syntax to verify that exceptions get thrown. It looks pretty, but I'm not a fan of dynamic proxies. That said, there syntax is so slick it remains tempting:
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
// then: catch the exception if any is thrown
catchException(myList).get(1);
// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;
Lastly, for the situation that I ran into to get to this thread, there is a way to ignore tests if some conidition is met.
Right now I'm working on getting some DLLs called through a java native-library-loading-library called JNA, but our build server is in ubuntu. I like to try to drive this kind of development with JUnit tests --even though they're far from "units" at this point--. What I want to do is run the test if I'm on a local machine, but ignore the test if we're on ubuntu. JUnit 4 does have a provision for this, called Assume:
#Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
//this line will cause the test to be branded as "ignored" when "isCircleCI"
//(the machine running ubuntu is running this test) is true.
Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
//an ignored test will typically result in some qualifier being put on the results,
//but will also not typically prevent a green-ton most platforms.
//setup
URL url = DLLTestFixture.class.getResource("USERDLL.dll");
String path = url.toURI().getPath();
path = path.substring(0, path.lastIndexOf("/"));
//act
NativeLibrary.addSearchPath("USERDLL", path);
Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
//assert
assertThat(dll).isNotNull();
}
I was looking for pass method for JUnit as well, so that I could short-circuit some tests that were not applicable in some scenarios (there are integration tests, rather than pure unit tests). So too bad it is not there.
Fortunately, there is a way to have a test ignored conditionally, which actually fits even better in my case using assumeTrue method:
Assume.assumeTrue(isTestApplicable);
So here the test will be executed only if isTestApplicable is true, otherwise test will be ignored.
There is no need for the pass method because when no AssertionFailedException is thrown from the test code the unit test case will pass.
The fail() method actually throws an AssertionFailedException to fail the testCase if control comes to that point.
I think that this question is a result of a little misunderstanding of the test execution process. In JUnit (and other testing tools) results are counted per method, not per assert call. There is not a counter, which keeps track of how many passed/failured assertX was executed.
JUnit executes each test method separately. If the method returns successfully, then the test registered as "passed". If an exception occurs, then the test registered as "failed". In the latter case two subcase are possible: 1) a JUnit assertion exception, 2) any other kind of exceptions. Status will be "failed" in the first case, and "error" in the second case.
In the Assert class many shorthand methods are avaiable for throwing assertion exceptions. In other words, Assert is an abstraction layer over JUnit's exceptions.
For example, this is the source code of assertEquals on GitHub:
/**
* Asserts that two Strings are equal.
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null) {
return;
}
if (expected != null && expected.equals(actual)) {
return;
}
String cleanMessage = message == null ? "" : message;
throw new ComparisonFailure(cleanMessage, expected, actual);
}
As you can see, in case of equality nothing happens, otherwise an excepion will be thrown.
So:
assertEqual("Oh!", "Some string", "Another string!");
simply throws a ComparisonFailure exception, which will be catched by JUnit, and
assertEqual("Oh?", "Same string", "Same string");
does NOTHING.
In sum, something like pass() would not make any sense, because it did not do anything.

Categories

Resources