CompletionStage.whenComplete() block of code is run and its results are ignored even if it throws an exception, but in my test case, I want it to break based on the exception.
How do I test it? I'm able to simulate assertion-based exception from internal code but the exception is ignored and hence test cases do not fail.
return orderService.newOrder(order, request)
.whenComplete((__, throwable) -> {
if (throwable == null) {
eventPublisher.publishEvent(orderSummary.getOrderId());
}
});
Related
When I remove the try/catch it works but cannot test negative test
public class TileCombinationSetsTest {
#Test public void testTileCombinations() {
new TileCombinationSets();
assertEquals(TileCombinationSets.tileCombinations(1).size(), 7);
assertEquals(TileCombinationSets.tileCombinations(2).size(), 42);
assertEquals(TileCombinationSets.tileCombinations(3).size(), 210);
assertEquals(TileCombinationSets.tileCombinations(4).size(), 840);
assertEquals(TileCombinationSets.tileCombinations(5).size(), 2520);
assertEquals(TileCombinationSets.tileCombinations(6).size(), 5040);
assertEquals(TileCombinationSets.tileCombinations(7).size(), 5040);
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Throwable e) {}
}
}
In JUnit a test fails when the test method throws an exception (or an other Throwable). JUnit's test runner catches the exception and reports the test as failed. On the other hand the test runner considers a test to be successful when the test method finishes without throwing an exception. Statements like assertEquals and fail throw an AssertionError.
In your test fail("Exceptions expected") is throwing an AssertionError. which is immediately caught and and therefore the test method testTileCombinations doesn't throw an exception. Now for JUnit it looks like the method was executed successfully and therefore it considers the test to be successful.
If you want to test that TileCombinationSets.tileCombinations(4) throws an exception then you can use JUnit's assertThrows
assertThrows(
Exception.class, // you can be more specific here
() -> TileCombinationSets.tileCombinations(4)
);
If you want to test that TileCombinationSets.tileCombinations(4) doesn't throw an exception then you simply execute it. (JUnit will report the test as failed if it throws an exception and successful otherwise.)
#Test
public void testTileCombinations() {
...
TileCombinationSets.tileCombinations(4);
}
I assume the part
TileCombinationSets.tileCombinations(4)
throws an exception the second time it is executed.
You could print the stacktrace of the exception to see if an exception is thrown.
Without knowing what TileCombinationSets.tileCombinations(int x) does its hard to say.
If possible could you post the method?
You should generally not catch Throwable but Exception instead. Throwable also includes subclasses of Error, which are critical errors concerning that Java Runtime Environment itself (like OutOfMemoryError), from which a program should not attempt to recover because it puts the program into an undefined state.
As it happens, the AssertionError that is thrown by the fail() method in your example
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Throwable e) {}
also extends Error.
So by changing your code to
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Exception e) {}
it should behave as intended, as long as the exceptions thrown by your tileCombinations() method only extend Exception (which they should, as it is bad practice to extend Error yourself).
In the following method, I am purposely making the call c.rxCommit() throw an exception during test.
The exception is thrown as expected, but I never land in the onErrorResumeNext block as expected.
I am expecting to land inside here to handle the error and perform some rollback.
Can I get some advice as to why I am not landing within the error block? Thanks.
public Observable<Void> myMethod(Observable<Map<String, String>> records) {
return client.rxGetConnection()
.flatMapCompletable(c -> c.rxSetAutoCommit(false)
.toCompletable()
.andThen(records.flatMapSingle(record -> perform(c, record)).toCompletable())
.andThen(c.rxCommit().toCompletable()) // test makes this c.rxCommit() throw an error on purpose.
.onErrorResumeNext(throwable -> {
// I want to land in here when error but it is not happening.
return c.rxRollback().toCompletable();
})
.andThen(c.rxSetAutoCommit(true).toCompletable())
.andThen(c.rxClose()).toCompletable()
).toObservable();
}
The test
#Test
void test() {
when(sqlConnection.rxCommit()).thenThrow(new RuntimeException("Error on Commit")); // mockito
myClass.myMethod(mockedRecords).subscribe(
success -> System.out.println(),
throwable -> System.out.println("err " + throwable), // I land in here with the new RuntimeException("Error on Commit") exception.
// this is wrong. Error should have been handled in the onErrorResumeNext block and should be getting success here instead.
);
// some verify() to test outcome
}
As akarnokd says, your sqlConnection.rxCommit() mock is wrong, because it throws exception right after method call, not by subscription.
If want to receive error in rx flow, try this:
when(sqlConnection.rxCommit()).thenReturn(Single.error(RuntimeException("Error on Commit")));
But if you really want to throw exceptions in rxCommit(), try to wrap it in Single.defer:
.andThen(
Single.defer(() -> {
return c.rxCommit().toCompletable();
})
I am trying to write a test case for a method which throws an exception based on certain logic. However the test case fails as the expected exception and obtained exceptions are different.
Method to test -
public void methodA (//parameters) throws ExceptionA
{
certainlogic=//call some method
if (certainlogic)
throw new ExceptionA(//exception details)
else
//code snippet
}
Test method -
#Test (expected=ExceptionA.class)
public void testMethodA
{
try
{
when (//mock method).thenReturn(true);
//call methodA
}
catch (ExceptionA e)
{
fail(e.printStackTrace(e));
}
}
I am receiving the below error -
Unexpected exception, expected<cExceptionA> but was<java.lang.AssertionError>
How do I solve this issue?
You have to remove the catch in your test
#Test (expected=ExceptionA.class)
public void testMethod()
{
when (//mock method).thenReturn(true);
//call methodA
}
Otherwise you catch the ExceptionA and by calling fail you throw an AssertionError. Obviously the AssertionError is not an ExceptionA and therefore your test fails.
You should remove the try-catch block entirely or at least the catch.
The "expected = ExceptionA.class" tells junit to monitor for thrown exceptions, catch them and compare their class against the given class.
If you catch the thrown exception, the #Test-annotated junit method cannot detect if such an exception is thrown.
By calling fail(...) you implicitly throw an AssertionError which junit detects and thus your test fails because AssertionError.class != ExceptionA.class
I have a code segment like shown below. Each line of code throw same exception. However, in practice, when first line throws an exception, testFoo finishes its job and does not continue, as expected. But, I want a bit more different thing; since they are throwing same exception, I want to continue and check these three lines w.r.t the exception which they all throw. If they throw, test should be continue.
How can I test these three line w.r.t same exception?
#test
void testFoo(){
assertNull( /*errorMessage*/, ClassFoo.foo(null)); // foo will throw `AssertionError` due to null parameter
assertNull( /*errorMessage*/, ClassBar.bar(null)); // foo will throw `AssertionError` due to null parameter
assertNull( /*errorMessage*/, ClassGbr.gbr(null)); // foo will throw `AssertionError` due to null parameter
}
Just catch the exception yourself:
#Test
void testFoo() {
boolean fooHasThrownException = false;
boolean barHasThrownException = false;
boolean gbrHasThrownException = false;
try {
ClassFoo.foo(null);
fail();
} catch (AssertionError e) {
fooHasThrownException = true;
}
try {
ClassBar.bar(null);
fail();
} catch (AssertionError e) {
barHasThrownException = true;
}
try {
ClassGbr.gbr(null);
fail();
} catch (AssertionError e) {
gbrHasThrownException = true;
}
assertThat(true, equalTo(fooHasThrownException),
equalTo(barHasThrownException),
equalTo(gbrHasThrownException));
}
Note that your assertNull() is redundant. If a method throws an exception, it will not return anything.
On the side, this is a very weird scenario to be testing. If a method throws an exception, it just seems more logical to stop any further processing, if those processes down the line are going to also throw exceptions anyway.
I have tried to implement precondition for each parameters to a method with Java built-in Assert.assertTrue...
This is not built into java, this is from junit: void junit.framework.Assert.assertTrue(...). You are confusing Java Assertions with Junit assertions.
Junit assertions should be used in your unit tests. They look like Assert.assertEquals(result, "expected result"); They are intended to test the validity of the methods under test in your unit tests.
Java assertions should be used when verifying assumptions. They look like assert param!=null:"param should not be null!"; They are part of the java language and can be turned on and off at compile time. They are intended to double check assumptions in your code and to produce zero overhead when turned off.
Programming with assertions is a great thing. Using Junit assertions outside of unit tests is dubious.
My interpretation of this question is that you are expecting an AssertFailedError in your unit test and this is meant to be part of this test. If that is the case, you can use the following junit method structure:
#Test(expected = AssertFailedError.class)
public void testFoo() throws AssertFailedError
{
assertNotNull(null);
}
You can use this when you are testing a block of code that you know will throw an exception.
I have some unit tests which exercise code which makes calls out to a test server, in order to make sure that the requests are well-formed (i.e. we get valid data back in response). However, this means that the unit tests, and hence the build, can get blocked if this test server is down. This does not conform to good unit test practices, but as a thought experiment let's say I'm not allowed to delete these tests or change them so they don't actually call out to the server. I want to change them so that they will still pass if the server is down (i.e. trying to connect results in ConnectException), but fail if any other exception occurs. Making it more difficult, the code under test doesn't throw the ConnecException directly, but throws a wrapper exception that contains it. So initially, that means each test will go from looking like this:
#Test
public void testNumberOne() {
// body of test...
}
To this:
#Test
public void testNumberOne() {
try {
// body of test...
} catch (ThirdPartyWrapperException e) {
if (!(e.getRootCause() instanceof ConnectException) {
throw e;
}
}
}
Is there any way I can avoid having to paste that try/catch into each unit test?
I know I can refactor out at least some of it, ala:
#Test
public void testNumberOne() {
try {
// body of test...
} catch (ThirdPartyWrapperException e) {
handleException(e);
}
}
private void handleException(ThirdPartyWrapperException e)
throws ThirdPartyWrapperException {
if (!(e.getRootCause() instanceof ConnectException) {
throw e;
}
}
But is there anything further I can do?
I would add a line to the start to determine if the required resources are available
#Test
public void testNumberOne() {
if (!requiredServerAvailable()) return;