The line within <s></s> causes a ClassNotFoundException to be thrown and must be handled in order to compile. If I resolve the compile error by surrounding with try-catch then each unit test will be working with an uninitialized instance if the exception was thrown. What would happen if I add throws to the method signature?
#Test
public class PanelControllerTest {
private PanelController panelController;
#BeforeTest
public void beforeTest() {
panelController = <s>new PanelController();</s>
}
}
I'm new to test fixtures and I'm assuming this would be a correct way to test an instance of the class. What's the best way to handle exceptions inside the test fixture setup code?
UPDATE:
This seems to be the source of the exception called from PanelController:
class DBAccess {
public DBAccess(DBConnection dbConnection) throws ClassNotFoundException {
Class.forName(Constants.jdbcDriver);
...
}
}
The correct behavior is to capture the exception and fail the test run.
#BeforeTest
public void beforeTest() {
try{
panelController = new PanelController();
} catch (Exception e) {
fail("Test failed because dependency could not be instantiated. Exception was:"+e.getMessage());
}
}
In an ideal world you probably wouldn't be dependent on a db (because it's hard to manage their state for testing) when running tests, but use a mock object instead. Still, if you have to rely on it best to fail the test run if the db is out of order, and surface that as a direct failure.
Related
In my business logic I don't have any scenario for exception, Not sure how to test the catch block in sprint boot Service class. Most of the scenarios are handled in controller level.
But for sonar coverage I need to cover catch block too in my services.
My sample code be like
public void employeeDetails(Object Employee) throws CustomException {
try {
int count = commonUtils.calculateEmployeeCount(Employee)
} catch (Exception e) {
throw new CustomException(" Exception occurred", e);
}
}
Whether my business logic should have any failure scenarios to test or we have any option to mock custom virtual exception for testing purpose. Any one please advice on this.
Reference
How do you assert that a certain exception is thrown in JUnit 4 tests?
How to Junit test a try catch block in my code
I assume a class EmployeeServiceImpl implementing EmployeeService with the method void EmployeeDetails(Object Employee). Note, according to the code conventions, the names of methods start with lower-case, so I will follow such convention in my answer.
public void employeeDetails(Object employee) throws CustomException {
try {
int count = calculateEmployeeCount(employee)
} catch (Exception e) {
throw new CustomException("Exception occurred", e);
}
}
You need to achieve calculateEmployeeCount method to throw an exception, which can be any subtype of Exception. For that you need instance of the class having such method. The instance should be either mocked using #MockBean or if it's our EmployeeServiceImpl, you use #SpyBean for partial mocking instead of #Autowired for a production bean with injected beans with precedence of the test ones (#MockBean) over the production ones.
Assuming you use Spring tests starter with Mockito and the same class having calculateEmployeeCount method (judging from its name).
#SpyBean
private EmployeeService employeeService;
Mockito.when(employeeService.calculateEmployeeCount())
.thenThrow(new Exception("An exception"));
The final step is a verification of whether the CustomException was thrown:
Object employee = new Object(); // it doesn't need to be a mock
CustomException exception = Assertions.assertThrows(
CustomException.class,
() -> employeeService.employeeDetails(employee));
// the thrown exception is available fur further testing (of the message, cause etc.)
I wrote some test cases to test some method. But some methods throw an exception. Am I doing it correctly?
private void testNumber(String word, int number) {
try {
assertEquals(word, service.convert(number));
} catch (OutOfRangeNumberException e) {
Assert.fail("Test failed : " + e.getMessage());
}
}
#Test
public final void testZero() {
testNumber("zero", 0);
}
If I pass -45, it will fail with OutOfRangeException but I am not able to test specific exception like #Test(Expected...)
An unexpected exception is a test failure, so you neither need nor want to catch one.
#Test
public void canConvertStringsToDecimals() {
String str = "1.234";
Assert.assertEquals(1.234, service.convert(str), 1.0e-4);
}
Until service does not throw an IllegalArgumentException because str has a decimal point in it, that will be a simple test failure.
An expected exception should be handled by the optional expected argument of #Test.
#Test(expected=NullPointerException.class)
public void cannotConvertNulls() {
service.convert(null);
}
If the programmer was lazy and threw Exception, or if he had service return 0.0, the test will fail. Only an NPE will succeed. Note that subclasses of the expected exception also work. That's rare for NPEs, but common with IOExceptions and SQLExceptions.
In the rare case that you want to test for a specific exception message, you use the newish ExpectedException JUnit #Rule.
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void messageIncludesErrantTemperature() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("-400"); // Tests that the message contains -400.
temperatureGauge.setTemperature(-400);
}
Now, unless the setTemperature throws an IAE and the message contains the temperature the user was trying to set, the test fails. This rule can be used in more sophisticated ways.
Your example can best be handled by:
private void testNumber(String word, int number)
throws OutOfRangeNumberException {
assertEquals(word, service.convert(number));
}
#Test
public final void testZero()
throws OutOfRangeNumberException {
testNumber("zero", 0);
}
You can inline testNumber; now, it does not help much. You can turn this into a parametrized test class.
Remove the try-catch block and add throws Exception to your test method, like:
#Test
public final void testZero() throws Exception {
assertEquals("zero", service.convert(0));
}
JUnit expects failing tests will throw Exceptions, your catching them is just stopping JUnit from being able to report them properly. Also this way the expected property on the #Test annotation will work.
You don't need to catch the exception to fail the test. Just let it go (by declaring throws) and it will fail anyway.
Another case is when you actually expect the exception, then you put fail at the end of try block.
For example:
#Test
public void testInvalidNumber() {
try {
String dummy = service.convert(-1));
Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.")
} catch (OutOfRangeException e) {
// expected
}
}
You can use this kind of test to verify if your code is properly validating input and handles invalid input with a proper exception.
There are several strategies that are open to you to deal with expected exceptions in your tests. I think the JUnit annotations and try/catch idiom have already been mentioned above. I'd like to draw attention to the Java 8 option of Lambda expressions.
For instance given:
class DummyService {
public void someMethod() {
throw new RuntimeException("Runtime exception occurred");
}
public void someOtherMethod(boolean b) {
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
}
You can do this:
#Test
public void verifiesCauseType() {
// lambda expression
assertThrown(() -> new DummyService().someOtherMethod(true))
// assertions
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasCauseInstanceOf(IllegalStateException.class);
}
Take a look at this blog which covers most of the options with examples.
http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html
And this one explains the Java 8 Lambda option more fully:
http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
I've tests where based on some condition, I skip execution in #BeforeClass itself like -
#BeforeClass(alwaysRun = true)
public void beforeClass() {
super.beforeClass();
if (someCondition) {
//do something
} else {
throw new SkipException(
"THESE TESTS ARE NOT INTENDED TO EXECUTE: ");
}
}
}
#BeforeMethod
public void beforeMethod() {
// do something
}
But when I run tests, skipExecution statement is executed still execution goes in method annotated with #BeforeMethod and code under it is executed which results my tests in failure instead of skip status.
This issue does not reproduce if I try it out of our automation framework and reproduces only when I try it out with my framework code. Looks somewhere, the exception I'm throwing, is being caught. Actually in my code, I'm not catching it anywhere. I went all the way up to parent classes, still I cannot see exception being caught.
Is there any way using Java APIs with which I can identify where the exception is caught?
I use this construction:
try {
Mockito.when(rules1.onEvent(Mockito.<OnEventArgs>any(), Mockito.<Response>any())).thenReturn(true);
} catch (MalformedEventException e) {
Assert.fail();
}
For mocking this interface:
public interface Rules {
boolean onEvent(OnEventArgs onEventArgs, Response response) throws MalformedEventException;
}
However, I don't understand why I have to catch the Exception when using Mockito#when in my test? The exception should never be thrown in the "declaration" of the mock, right? So why do I have to deal with it there? ...And how should I handle it? Assert.fail()?
Mockito builds a proxy which must fulfill the signatures of the methods of the mocked class. Thrown exceptions are part of this signature. You can omit the try/catches by declaring throws Exception for your test method.
The exception of the mocked object will normally be not thrown, of course. This is only possible if you use thenCallRealMethod().
You don't need to catch the exception:
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.when;
...
#Test
public void something() throws Exception {
when(rules1.onEvent(isA(OnEventArgs.class), isA(Response.class)).thenReturn(true);
...
}
If the test throws any exception, JUnit will report a failure.
I saw people using "throws Exception" in tests, but I never do. Should I worry? I never had any issues with that. What's the difference?
#Test()
public void test() throws Exception
{
//Do something
}
or
#Test()
public void test()
{
//Do something
}
If the code you are testing throws an exception, you must handle it in some way. Either by declaring a "throws Exception" in the method signature, or by using try-catch.
If the code you are calling in the method does not throw any exceptions, then you dont need either of those. The compiler will let you know if you need to catch an exception in some way.
Also note that you can do tests that makes sure an exception is thrown, see this answer
junit will mark a test as being in "error state" if an exception is thrown from that method. For most usecases, this is essentially the same as failing a test (in the sense that a test that completed in error state did not succeed). A lot of test authors don't like the hassle (or the code-uglification) associated with handling checked exceptions.
E.g., Consider a test that should run a couple of methods and assert the end state of an object:
public class SomeTest
SomeObject so;
#Before
public void setUp() {
so = new SomeObject();
}
#Test
public void TestSomeFlow() {
try {
so.init();
// must catch in order to avoid a compilation error
} catch (InitExceptionIDontCareAbout e) {
fail ("init failed");
}
try {
so.doSomething();
// must catch in order to avoid a compilation error
} catch (SomeOtherExceptionIDontCareAbout e) {
fail ("doSomething failed");
}
assertTrue ("doSomething didn't work", so.isSomethingDone());
}
}
Now consider how much cleaner the code looks without exception handling:
public class SomeTest
SomeObject so;
#Before
public void setUp() {
so = new SomeObject();
}
// Any exception throwm will mean the test did not succeed
#Test
public void TestSomeFlow() throws Exception {
so.init();
so.doSomething();
assertTrue ("doSomething didn't work", so.isSomethingDone());
}
}
Functionally, there is no difference. It only means that the compiler wont complain if you throw a non-RuntimeException. Since JUnit will catch any exception thrown by the test method anyway, it does not really matter.
However, it is usually considered a better practice to catch the Exception yourself and use the fail method of JUnit, in which case you do not need the throws clause.