What happens with the Executable in a JUnit assertThrows? - java

I understand that Junit5 Assertions.assertThrows accepts an Executable type object. So for a simple example where a Constructor may not take an empty string as a name parameter:
public Company(String aName, Calendar aFoundingDate)
{
if (aName == null || aName.length() == 0 || aName.length() > 50) {
throw new IllegalArgumentException("Invalid name");
}
this.name = aName;
foundingDate = aFoundingDate;
}
I can write a test like this:
// Company constructor test
#Test
void testCompanyConstructor() {
// Given
String emptyName = "aabbe";
Calendar validFoundingDate = Calendar.getInstance();
validFoundingDate.set(2000, 1, 1);
// Then
assertThrows(IllegalArgumentException.class, () -> new Company(emptyName, validFoundingDate));
}
What I wonder is, what happens to the executable, i.e. the Lambda Expression?
Does JUnit call execute() on the Lambda expression and in doing so, the anonymous company Object with the empty name is created and the exception is
Appendix:
These versions are equivalent:
// Company constructor test
#Test
void testCompanyConstructor() {
// Given
String emptyName = "";
Calendar validFoundingDate = Calendar.getInstance();
validFoundingDate.set(2000, 1, 1);
// Then
Executable executable = new Executable() {
public void execute() {
new Company(emptyName, validFoundingDate);
}
};
assertThrows(IllegalArgumentException.class, executable);
assertThrows(IllegalArgumentException.class, () -> new Company(emptyName, validFoundingDate));
}

When inspecting the code of assertThrows we can see that deeply there is such code placed in AssertThrows::assertThrows:
try {
executable.execute();
}
catch (Throwable actualException)
if (expectedType.isInstance(actualException)) {
return (T) actualException;
}
else {
BlacklistedExceptions.rethrowIfBlacklisted(actualException);
String message = buildPrefix(nullSafeGet(messageOrSupplier))
+ format(expectedType, actualException.getClass(), "Unexpected exception type thrown");
throw new AssertionFailedError(message, actualException);
}
}
so it basically invokes Executable and catches Throwable that might be thrown and returns it. If no exception was thrown or the type of exception is different than expected - the assertion fails.

Yes that's precisely what happens. JUnit runs the Executable inside a
try { ... } catch (Throwable t) {...} block. If the exception caught is of the specified type, then all is good. If not then it throws an AssertionError.

Related

Java spock - how to test catch() block that doesnt throw exception back [duplicate]

This question already has an answer here:
How to use mock in a private static final variable in Spock?
(1 answer)
Closed 5 months ago.
How to test the below java catch block where in catch() doesnt throw exception back.
class ErrorTransImpl {
private static final Logger logger = Logger.getLogger(ErrorTransImpl.class);
public int errorCatcher(ErrorTrans transError){
int ct = 0;
if (transError != null){
String query = "INSERT INTO tab_1 (rw1,rw2,rw3,rw4,rw5) VALUES (?,?,?,?,?)";
try {
ct = jdbcTemplate.update(query, new Object[] {transError.col1(),transError.col2(), transError.col3(),transError.col4(),transError.col5()});
}catch (DataAccessException ex) {
logger.error(ex);
}
}
return ct;
}
}
I tried testing as below, but:
1>Unable to get into catch block.
2> Unable to test catch() even if inside as it doesnt throw exception back.
def 'throw DataAccess Exception upon incorrect update'() {
given:
def log = Mock(Logger)
def originalLogger = ErrorTransImpl.logger
ErrorTransImpl.logger = log
ErrorTransImpl errTransImpl = Spy() {
jdbcTemplate >> {
throw new DataAccessException() {
#Override
String getMessage() {
return super.getMessage()
}
}
}
}
when:
errTransImpl.errorCatcher(new ErrorTrans())
then:
// thrown DataAccessException
//Not sure what to assert or test here ??
}
Can anyone help on how i test this?
You need to test the behaviour that
ct = jdbcTemplate.update(query, new Object[] {transError.col1(),transError.col2(), transError.col3(),transError.col4(),transError.col5()});
failed. Or, I don't really like this myself, you can check that the logger.error() was called.

How can I test exception in completable future?

I have been converting some code to be asynchronous. The original unit test used the annotation #Test(expected = MyExcpetion.class) but I don't think this will work because the exception I want to assert on is wrapped in java.util.concurrent.ExcutionException . I did try calling my future like this but my assertion is still failing and I don't love that I had to add in return null
myApiCall.get(123).exceptionally((ex) -> {
assertEquals(ex.getCause(),MyCustomException.class)
return null
}
I also tried this flavor but still not working
myApiCall.get(123).exceptionally((ex) -> {
assertThat(ex.getCause())
.isInstanceOF(MyException.class)
.hasMessage("expected message etc")
return null;
}
My API just throws exception if it can't find id. How should I be properly testing this? Can I use that original annotation in anyway?
my api call reaches out to db when run. In this test I am setting up my future to return an error so it doesn't actually try to communicate with anything. the code under test looks like this
public class myApiCall {
public completableFuture get(final String id){
return myService.getFromDB(id)
.thenApply(
//code here looks at result and if happy path then returns it after
//doing some transformation
//otherwise it throws exception
)
}
}
in the unit test I force myService.getFromDB(id) to return bad data so I can test exception and also keep this a unit test don't reach out to db etc.
Let's assume your API throws if called with 0:
public static CompletableFuture<Integer> apiCall(int id) {
return CompletableFuture.supplyAsync(() -> {
if (id == 0) throw new RuntimeException("Please not 0!!");
else return id;
});
}
You can test that it works as expected with the following code (I'm using TestNG but I suspect it won't be too difficult to translate into a JUnit test):
#Test public void test_ok() throws Exception {
CompletableFuture<Integer> result = apiCall(1);
assertEquals(result.get(), (Integer) 1);
}
#Test(expectedExceptions = ExecutionException.class,
expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
result.get();
}
Note that the second test uses the fact that the ExecutionException message will contain the original exception type and message and captures the expectation with a regex. If you can't do that with JUnit, you can call result.get() in a try/catch block and call throw e.getCause(); in the catch block. In other words, something like this:
#Test(expectedExceptions = RuntimeException.class,
expectedExceptionsMessageRegExp = "Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
try {
result.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
You can try also alternative option:
import org.hamcrest.core.IsInstanceOf;
import org.junit.rules.ExpectedException;
public class Test() {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void myApiCallTest() {
thrown.expect(ExcutionException.class);
thrown.expectCause(IsInstanceOf.instanceOf(MyException.class));
thrown.expectMessage("the message you expected");
myApiCall.get("");
}
}
Assuming that:
public class myApiCall {
public completableFuture get(final String id) {
// ...
throw new ExcutionException(new MyException("the message you expected"))
}
}
Assume that you have a class and you want to test a method which returns a completable future:
public class A {
private final Api api;
public A(Api api) { this.api = api;}
public CompletableFuture<Void> execute(Integer input) {
final CompletableFuture<Void> future = api.execute(input)
.thenApplyAsync(result -> doSomething())
.exceptionally(ex -> doFailure());
return future;
}
}
To test the execution of "doSomething()" then you may use mockito and do the following:
// prepare test
final Api api = mock(Api.class)
final A a = new A(api);
when(api.execute(any(Integer.class)))
.thenReturn(CompletableFuture.completedFuture(null));
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
...
To test "doFailure" do the following:
when(api.execute(any(Integer.class))).thenAnswer(answer -> {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
});
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
assertTrue(result.isCompletedExceptionally());
that is easy thing doing in junit-4. Are you remember the #RunWith annotation? Yes, write your own TestRunner to intercept the exception before the junit expected exception processor is invoked, for example:
public class ConcurrentRunner extends BlockJUnit4ClassRunner {
public ConcurrentRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected Statement possiblyExpectingExceptions(FrameworkMethod method,
Object test,
Statement next) {
return super.possiblyExpectingExceptions(
method, test, throwingActualException(next)
);
}
private Statement throwingActualException(Statement next) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
next.evaluate();
} catch (ExecutionException | CompletionException source) {
throw theActualExceptionOf(source);
}
}
private Throwable theActualExceptionOf(Exception source) {
return source.getCause() != null ? source.getCause() : source;
}
};
}
}
just annotated with #RunWith(ConcurrentRunner.class) on the test, you needn't change your test code at all. for example:
#RunWith(ConcurrentRunner.class)
public class ConcurrentExpectedExceptionTest {
#Test(expected = IllegalArgumentException.class)
public void caughtTheActualException() throws Throwable {
myApiCall().join();
}
private CompletableFuture<Object> myApiCall() {
return CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
}
}

How to check multiple exceptions with one JUnit Method?

i have this code in my program which is needed to be tested with jUnit
void deleteCustomer(String name) throws UnknownCustomerException,
AccountNotEmptyException {
if (name == null) {
throw new NullPointerException();
} else if (!exists(name)) {
throw new UnknownCustomerException();
} else if (getCustomer(name).deletable()) {
customerList.remove(getCustomer(name));
}
}
I thought i can test it in one JUnit method like
#Test
public void createCustomer(){
System.out.println("createCustomerTest");
try {
element.createCustomer(null);
//fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (NullPointerException anIndexOutOfBoundsException) {
assertTrue(anIndexOutOfBoundsException.getMessage().equals("NullPointerException"));
}
}
As you can see I already tried unsuccessfully to implement the NPE.
How can I check for several Exceptions in one JUnit Method? I checked some How-To's in the web but failed with that too.
I think in your case you should have separate tests, however you can achieve this like so if using Java 8:
Using an AssertJ 3 assertion, which can be used alongside JUnit:
import static org.assertj.core.api.Assertions.*;
#Test
public void test() {
Element element = new Element();
assertThatThrownBy(() -> element.createCustomer(null))
.isInstanceOf(NullPointerException.class)
.hasMessageContaining("NullPointerException");
assertThatThrownBy(() -> element.get(1))
.isInstanceOf(IndexOutOfBoundsException.class);
}
It's better than #Test(expected=IndexOutOfBoundsException.class) or .expect syntax because it guarantees the expected line in the test threw the exception and lets you check more details about the exception, such as message.
Maven/Gradle instructions here.
Write for each exception its own test. It will be only one thrown at a time anyway.
For example a simplified method:
void deleteCustomer( String name ) throws UnknownCustomerException
{
if ( name == null )
{
throw new NullPointerException();
}
else if ( !exists( name ) )
{
throw new UnknownCustomerException();
}
}
You have then two tests that each check if its exception is thrown:
#Test( expected = NullPointerException.class )
public void deleteCustomer_shouldThrowNullpointerIfNameIsNull() throws UnknownCustomerException
{
String name = null;
cut.deleteCustomer( name );
}
#Test( expected = UnknownCustomerException.class )
public void deleteCustomer_shouldThrowUnknownCustomerExceptionIfNameIsUnknown() throws UnknownCustomerException
{
String name = "someUnknownName";
cut.deleteCustomer( name );
}
The problem with the NullpointerException is, that the test is true/successful/green if the NPE is thrown anywhere in the method - so you should make sure, that that is not happening for the test to be meaningful.
You could add several "catch" statement into the test method for different exceptions, like:
try {
element.createCustomer(null);
Assert.fail("Exception was expected!");
} catch (NullPointerException _ignore) {
} catch (UnknownCustomerException _ignore) {
}
or with Java 87
try {
element.createCustomer(null);
Assert.fail("Exception was expected!");
} catch (NullPointerException | UnknownCustomerException _ignore) {
}
But if you switch from JUnit to TestNG, then your test will be much cleaner:
#org.testng.annotations.Test(expectedExceptions = { NullPointerException.class, UnknownCustomerException.class })
public void createCustomer() throws NullPointerException, UnknownCustomerException {
element.createCustomer(null);
}
More information about "expectedException" is here: http://testng.org/doc/documentation-main.html and example of the usage can be found here: http://www.mkyong.com/unittest/testng-tutorial-2-expected-exception-test/
I suggest that you take a closer look at the JavaDoc of ExpectedException and implement different tests for different validations, e.g.
public class CustomerTest {
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void throwsNullPointerExceptionForNullArg() {
exception.expect(NullPointerException.class);
element.createCustomer(null);
}
#Test
public void throwsUnknwonCustomerExceptionForUnkownCustomer() {
exception.expect(UnknownCustomerException.class);
// exception.expectMessage("Some exception message"); uncomment to verify exception message
element.createCustomer("unknownCustomerName");
}
#Test
public void doesNotThrowExceptionForKnownCustomer() {
element.createCustomer("a known customer");
// this test pass since ExpectedException.none() defaults to no exception
}
}

Chaining side effects from spock stub with void return type

I'm trying to test the following (contrived) code, which makes a call, and attempts one retry, if the call fails.
public class MyObject
{
public void process(final Client client) throws IOException
{
try
{
client.send();
}
catch (IOException e)
{
client.fix();
}
try
{
client.send();
}
catch (IOException e)
{
throw new IOException(e);
}
}
public class Client
{
public void send() throws IOException {}
public void fix() {}
}
}
My testing strategy is to mock the client object and stub a response that will throw an exception on the first call to send() and then succeed on the second attempt.
Using spock, I have the following:
def "test method calls"() {
setup:
def MyObject myObject = new MyObject()
def Client client = Mock(Client)
when:
myObject.process(client)
then:
2 * client.send() >>> {throw new IOException()} >> void
}
I've tried the above, and replacing void with null, and keep getting cast exceptions.
I've also tried:
2 * client.send() >>> [{throw new MyException()}, void]
How can I mock my desired response?
This test passes. I have added comments to show what each step indicates:
def "test method calls"() {
given:
def MyObject myObject = new MyObject()
def MyObject.Client client = Mock(MyObject.Client)
//The first time client.send() is called, throw an exception
1 * client.send() >> {throw new IOException()}
//The second time client.send() is called, do nothing. With the above, also defines that client.send() should be called a total of 2 times.
1 * client.send()
when:
myObject.process(client)
then:
noExceptionThrown() //Verifies that no exceptions are thrown
1 * client.fix() // Verifies that client.fix() is called only once.
}
Works fine.
1*getName()>>"Hello"
1*getName()>>"Hello Java"
First Invocation im getting "Hello".
Second Invocation im getting "Hello Java"

Test code with Exceptions and with no exceptions at same time (JAVA)

I am writing a test for already built java class function. I am writing tests using Testng and Mockito and have a Data Provider.
This is my Test
#Test(dataProvider = "myProvider", dataProviderClass = StaticDataProvider.class,
expectedExceptions = SomeException.class)
public void myControllerTest(String argument) throws Exception {
// Mocked object bussiness\
Boolean resultantObject = business.getList(argument);
Assert.assertTrue(resultantObject);
}
This is my Controller which I want to test
public Boolean controller(String argument) {
if(argument != null) {
throw new someException();
} else {
System.out.println("Sucess");
return true;
}
}
This is my Data Providor
#DataProvider(name = "myProvider")
public static Object[][] getDirectoryList() throws Exception {
Object[][] result = null;
// case1 throws SomeException
String testData1 = null;
// case2 don't throw exception
String testData2 = "String";
result = new Object[][] { { testData1 }, { testData2 } };
return result;
}
The problem here I am facing is, I don't want to create another test just to test both buggy and non buggy code and complete my test coverage using a single test case. But when I put Expected Exception on top, it fails on correct code, and when I dont, it fails on buggy code.
NOTE: This is example code and may not work, this is just to take an idea of scenario I am working on and what I am expecting.
Even if you ignore the "one test, one assertion" purist perspective, I think most people agree you should split tests that involve error conditions from tests that prove normal behaviour.
If you want to test multiple error conditions within one test (or if you're really keen on continuing with your plan), you can use this pattern:
try {
// something that should cause an exception
fail("Exception expected");
} catch (ExactlyTheRightException e) {
// ignored
}

Categories

Resources