Alternative to #Test(expected=ExceptionClass.class) for testing exceptions in testng - java

In TestNG, when we want to test a scenario in which an exception should be thrown one can write something like the following
#Test(expected=IndexOutOfBoundsException.class, expectedExceptionsMessageRegExp="*")
public void sampleExpectedExceptionTest() {
List emptyList = new ArrayList();
// Following line should throw an IndexOutOfBoundsException
emptyList.get(0);
}
I have seen that some people write the tests in following style.
#Test
public void sampleExpectedExceptionTest() {
// several lines here..
List emptyList = new ArrayList();
try {
emptyList.get(0);
Assert.assertFail("Expected IndexOutOfBoundsException but wasn't thrown");
} catch (IndexOutOfBoundsException e) {
// ignore
}
// ... more lines of code asserting exceptions similar to above try catch scenario
}
I dislike the above style primarily because it is very verbose and also because people using it usually write multiple tests in one test case. However, the argument given in it's favour is that it allows users to pinpoint the assertion to a particular line and hence it is better.
Recently I learnt about JUnit's #Rule annotation
public class SampleExceptionTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Test
public void sampleExpectedExceptionTest() {
List emptyList = new ArrayList();
exception.expect(IndexOutOfBoundsException.class);
emptyList.get(0);
}
}
This not only allows users to pinpoint the assertion to a line but it also discourages users to write multiple tests in one test case as once an exception is thrown the code exits and you can not test for multiple assertions. I want to know is there a similar option (or an idiom) in TestNG? I know that I can use expected

I suggest you have a look at the Catch-Exception library. It allows you to perform multiple assertions on the exception and any other relevant assertions. You can use it with JUnit and TestNG and any assertion framework you want.
Sample:
#Test
public void catchExceptionTest() {
// given: an empty list
List<Object> 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
Exception e = caughtException();
// Use JUnit, TestNG, AssertJ etc. assertions on the "e" exception
assert e instanceof IndexOutOfBoundsException;
}
You'll find more examples on the project page.

Related

How to throw JsonProcessingException while creating Json from List using Mockito?

I am trying to unit test catch block to convert List into Json format using jackson. Here is my code:
public String convert(List<POJO> list) {
ObjectMapper objectMapper = new ObjectMapper();
try {
data = objectMapper.writeValueAsString(list);
} catch (JsonProcessingException exception) {
System.out.println("Exception message: {}", exception.getMessage());
}
return data;
}
I tried unit testing this way:
#Mock
ObjectMapper mockObjectMapper;
#Test(expected = JsonProcessingException.class)
public void doThrowException() throws JsonProcessingException {
doThrow(JsonProcessingException.class).when(mockObjectMapper).writeValueAsString(any());
dataTransformer.convert(new ArrayList<>());
verify(mockObjectMapper.writeValueAsString(any()));
}
I have been trying to get my head around to cover this unit test for full coverage. I looked up couple of articles on SO, but no luck. Since I am new to unit testing world, I have a feeling that I am definitely missing something here.
1) Your test logic is not correct in respect of the implementation. In the implementation you catch the exception, so in the exception test case you will never get it as expected.
2) As said in the comment, you cannot mock ObjectMapper if the dependency is not visible from the client code of the class. Here it doesn't have any way to mock the class. You could add a constructor or a setter for setting that, but well does it make sense ?
3) Indeed you should not mock here. Your component under test maps some list elements to a String. You don't want to mock but test the mapping logic both in the exception cases and in the nominal cases. Otherwise your test will not have a great value.
To get the JsonProcessingException you could inspire from the excellent answers of this post.

checked exception is invalid for this method [duplicate]

This question already has answers here:
throw checked Exceptions from mocks with Mockito
(5 answers)
Closed 5 years ago.
I have the below class
There is an answer to this in StackOverflow but it deals with List throw checked Exceptions from mocks with Mockito. I like to look into this condition. Not getting where I am missing.
public SimpleClass{
private SimpleClass() {}
public void runMethod(request,String,Map,Object,Object) {
try {
doesSomething()....
}
}
catch(Exception e) {
String message = "" + request.getAttribute(X) + "Some message";
Logger.Log(param1 + param2 + message);
}
}
My Test method looks like below. I trying to run the coverage with the JUnit but the Catch Block is not covered, so Wrote the below test method. It throws the below exception. Not able to get where I am missing.
public class SimpleClassTest{
#Test
public void testCatchBlock() {
SimpleClass instanceObj = PowerMockito.mock(SimpleClass.class);
Mockito.doThrow(new Exception())
.when(instanceObj)
.runMethod(request, anyString(), anyMap(), anyObject(), anyObject());
}
}
Exception Thrown
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: java.lang.Exception
Edit
I am able to run the method by giving NullPointerException. When I try for code coverage with Junit, the catch block is completely shown as red, and the catch phrase is shown yellow. How do I achieve 100% coverage and how to test the String message in the catch block.
You are getting unit testing with mocking wrong. Here:
SimpleClass instanceObj =PowerMockito.mock(SimpleClass.class);
There is no point in mocking the class that is under test!
When you mock that class, you get a stub that has "nothing to do" with your real implementation. A "working setup" would look more like:
public void methodUnderTest(X x, ...) {
try {
x.foo();
} catch (Exception e) {
...
}
and
X mockedX = mock(X.class);
when(x.foo()).thenThrow(new WhateverException());
underTest.methodUnderTest(mockedX); ...
and then you could try to verify for example that the logger saw that expected logging call. In other words: you either use a mock to allow your code under test to do its job (with you being in control!) or to verify that some expected call took place on a mock object.
But as said: it doesn't make any sense to mock that class that you want to test. Because a mocked object doesn't know anything about the "real" implementation!
Manipulate the environment so that doesSomething() throws the Exception you want. Since we do not know what doesSomething() really does, one cannot say more.

How do I use JUnit's ErrorCollector to check how many failures have occurred?

I'm trying to use ErrorCollector in a unit test so that an assertion failure does not abort the test. Instead, I want to check the number of failures at the end of the test and only let the test fail if that number is greater than zero.
So my basic test looks like this:
#RunWith(AndroidJUnit4.class)
public class SampleAndroidTest {
#Rule
public ErrorCollector errors = new ErrorCollector();
#Test
public void testErrorCollector() throws Exception {
try {
assertEquals(1, 1); // should pass
} catch (Throwable t) {
errors.addError(t);
}
try {
assertEquals(1, 2); // should fail
} catch (Throwable t) {
errors.addError(t);
}
try {
assertEquals(1, 3); // should fail
} catch (Throwable t) {
errors.addError(t);
}
}
}
However, I'm not sure what to do with the errors object. The Javadocs for ErrorCollector do not indicate any methods to get the number of failures, etc. With the current approach, only the last failure is being shown.
I tried converting the object to a String by using toString(), but that only gives me a memory address and not any of the other stack traces. I'm sure there is a way to get the other stack traces and that the solution is simple, but I can't figure it out for the life of me.
After doing some more research, I found out that ErrorCollector actually prints all the failures at the end of the test. The reason that only the last failure was shown was due to the way Android Studio is designed. To get the other stack traces, one will have to view the Logcat output directly.

Test method that returns void

I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.

Testing for multiple exceptions with JUnit 4 annotations

Is it possible to test for multiple exceptions in a single JUnit unit test? I know for a single exception one can use, for example
#Test(expected=IllegalStateException.class)
Now, if I want to test for another exception (say, NullPointerException), can this be done in the same annotation, a different annotation or do I need to write another unit test completely?
You really want the test to do one thing, and to test for that. If you're not sure as to which exception is going to be thrown, that doesn't sound like a good test to me.
e.g. (in pseudo-code)
try {
badOperation();
/// looks like we succeeded. Not good! Fail the test
fail();
}
catch (ExpectedException e) {
// that's fine
}
catch (UnexpectedException e) {
// that's NOT fine. Fail the test
}
so if you want to test that your method throws 2 different exceptions (for 2 sets of inputs), then you'll need 2 tests.
This is not possible with the annotation.
With JUnit 4.7 you can use the new ExpectedException rule
public static class HasExpectedException {
#Interceptor
public ExpectedException thrown= new ExpectedException();
#Test
public void throwsNothing() {
}
#Test
public void throwsNullPointerException() {
thrown.expect(NullPointerException.class);
throw new NullPointerException();
}
#Test
public void throwsNullPointerExceptionWithMessage() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("happened?");
throw new NullPointerException("What happened?");
}
}
More see
JUnit 4.7: Interceptors: expected exceptions
Rules in JUnit 4.7
If updating to JUnit 4.7 is not possible for you, you have to write a bare unit test of the form
public test() {
try {
methodCall(); // should throw Exception
fail();
}
catch (Exception ex) {
assert((ex instanceof A) || (ex instanceof B) || ...etc...);
...
}
}
Although this is not possible with JUnit 4, it is possible if you switch to TestNG, which allows you to write
#Test(expectedExceptions = {IllegalArgumentException.class, NullPointerException.class})
Use catch-exception:
// test
public void testDo() {
// obj.do(1) must throw either A or B
catchException(obj).do(1);
assert caughtException() instanceof A
|| caughtException() instanceof B;
// obj.do(2) must throw A but not SubclassOfA
catchException(obj).do(2);
assert caughtException() instanceof A
&& !(caughtException() instanceof SubclassOfA);
}
#Test(expected=Exception.class)
This will throw all possible exceptions.
How would you expect to "expected"s to work? A method can only throw one exception.
You would have to write a different unit test for each way the method can fail. So if the method legitimately throw two exceptions then you need two tests set up to force the method of throwing each exception.
Keep the tests as simple and short as possible. The intention of a JUnit-Test is to test only one simple functionality or one single way of failure.
Indeed, to be safe, you should create at least one test for every possible execution way.
Normally, this is not always possible because if you have a method that analyses a string, there are so many possible string combinations that you cannot cover everything.
Keep it short and simple.
You can have 30-40 testing methods for one single method easily... does it really matter?
Regards

Categories

Resources