Test error handling method weirdness with Junit5 and mockito - java

I'm making unit tests for a method that does some exception handling. here's the simplified class I'd like to test:
class Foo{
private BarService bar;
public int MethodToTest(){
try{
bar.methodThatThrows();
return 1;
}catch(Exception e){
return 0;
}
}
}
And this is the unit test class.
class FooTest{
private IBarService barService = mock(BarService.class);
#Test
TestMethodToTest(){
when(barService.methodThatThrows()).thenThrow(new Exception("message");
Foo foo = new foo();
ReflectionTestUtils.setField(foo, "barService", barService);
assertEquals(foo.MethodToTest(), 0);
}
}
Somehow, when I run it, it fails because there is an error thrown (as expected), which has the exact same message as the message I put into the mocked service. When I run in debug mode, the catch block is not even run. How can this be possible?

Most likely you are throwing a checked exception in your test that is not declared for methodThatThrows
A message you declared in your test is indeed printed to the console, but the message is more informative:
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: java.lang.Exception: message
For example (IOException declared in BarService, but a more general checked exception thrown in the test code):
public class BarService {
public int methodThatThrows() throws IOException {
return 1;
}
}

You're not setting the BarService correctly in your example code. You're doing:
ReflectionTestUtils.setField(foo, "barService", barService);
But in the Foo class, the BarService variable is called "bar", and not "barService", so you need to do:
ReflectionTestUtils.setField(foo, "bar", barService);
Though the "correct" way to do this is to use Spring to autowire BarService into Foo, which allows you to avoid having to use ReflectionTestUtils in the first place.

Related

Runtime exceptions in Java 8 function

I'm using Java 8 Functions and converters and have the following:
Main class
public final class MainClass {
public MainClass(
final Function<InputModel, OutputModel> businessLogic,
final Converter<Input, InputModel> inputConverter,
final Converter<OutputModel, Output> outputConverter) {
this.businessLogic = requireNonNull(businessLogic, "businessLogic is null.");
this.inputConverter = requireNonNull(inputConverter, "inputConverter is null.");
this.outputConverter = requireNonNull(outputConverter, "outputConverter is null.");
}
/**
* Request Handler.
*/
public Output handleRequest(final Input input) {
requireNonNull(input, "input is null.");
log.info("input request: {}", input);
try {
return inputConverter
.andThen(businessLogic)
.andThen(outputConverter)
.apply(input);
} catch (final Exception ex) {
throw new InternalServiceException(ex.getMessage(), ex);
}
}
}
Unit test
public final class TestClass {
#Mock
private Function<InputModel, OutputModel> mockedBusinessLogic;
#Mock
private Converter<Input, InputModel> mockedInputConverter;
#Mock
private Converter<OutputModel, Output> mockedOutputConverter;
private MainClass mainClass = new MainClass(mockedBusinessLogic, mockedInputConverter, mockedOutputConverter);
#Test
public void handleRequest_SHOULD_throwException_WHEN_inputConverter_throwsException() {
final RuntimeException inputConverterException = new NullPointerException(EXCEPTION_MESSAGE);
// what should I mock here? apply or convert.. apply for `Converter` seems to be deprecated.
when(mockedInputConverter.convert(input))
.thenThrow(inputConverterException);
final Exception exception = assertThrows(
InternalServiceException.class,
() -> mainClass.handleRequest(input)
);
assertThat(exception.getMessage(), is(EXCEPTION_MESSAGE));
assertThat(exception.getCause(), is(inputConverterException));
}
}
The above assertions fail.
I expect that if the inputConverter throws an exception, the catch block in handleRequest would wrap it to InternalServiceException, but it doesn't seem to be happening.
Any help?
How do I actually write unit tests for handleRequest method? I want to test the behavior when either of inputConveter, businessLogic or outputConveter throws exception.
Everything in your code is a mock. When you call andThen on your mocked inputConverter, then either null or a new mock instance is returned (depending on configuration). Each andThen will return a new instance with the chained converters (at least that is what I assume)
Make sure you mock all required methods, or better, use real objects instantiated from real classes.
Setting breakpoints and then debugging should help you find the issue. If you set in your try-block, and then single-step through the code, you will see that the way mocks are used in your code will not work. You could also save each result of andThen in a variable and then check in the debugger what type each has. I'm pretty sure it will either be null or "Mock for class X".

How can I check if an internal service threw an exception?

I'm trying to write a unit test for a new service. The service returns void and uses other auto-wired services to do some work. I want to test a case where one of the internal services throws an exception which is caught by the top level service under test. How can I verify in the 'then' clause that the internal service threw an exception if it is caught by the service under test?
I would also like to verify that a static method was called to log the result, but I can't see a way to do that with Spock either. These are the only outputs for the service so I would like to verify that they are working.
To address the first part of your question:
Let's assume we have the following structure:
interface ServiceUnderTest {
void foo()
}
interface InternalService {
int bar() throws IllegalArgumentException
}
class ServiceUnderTestImpl implements ServiceUnderTest {
InternalService internalService
ServiceUnderTestImpl(InternalService internalService) {
this.internalService = internalService
}
void foo() {
try {
internalService.bar()
} catch(IllegalArgumentException ex) {
println "Got you"
}
}
}
You're testing method foo() in ServiceUnderTest and it returns void
So I suggest creating Stub of Internal Service that throws exception upon invocation of its bar method
The test will check that no exception has been thrown when calling foo (which means that the exception thrown by internal service was caught and handled correctly)
The test can look like this:
class SampleSpockTest extends Specification {
def "test sample" () {
given:
def internalService = Stub(InternalService)
def subject = new ServiceUnderTestImpl(internalService)
internalService.bar() >> {throw new IllegalArgumentException("Sample
exception")}
when:
subject.foo()
then:
noExceptionThrown()
}
}
I think that you shouldn't check in "then clause that the internal service threw an exception" as you say, actually you're checking the ServiceUnderTest. Its not optimal that it returns void, because you can't really know what did it do, maybe by checking its internal state after the invocation of method foo or something, but at least you can check that the exception was processed if internal service was called and threw and exception.
Regarding the static method mocking, you shouldn't do it probably, mocks do not play well with static calls. You can use "special" tools like PowerMock or PowerMockito, but I believe, they point on a code smell and should be primarily used for legacy code. Its only my opinion, though.

Unable to execute test method from mocked class

I am writing unit test for methods to find banks near my location.
I mocked the class and tried to call the methods.
But, control is not going to method to execute it.
Below is unit test case.
#Test
public void testFindBanksByGeo() {
String spatialLocation = "45.36134,14.84400";
String Address = "Test Address";
String spatialLocation2 = "18.04706,38.78501";
// 'SearchClass' is class where 'target' method resides
SearchClass searchClass = Mockito.mock(SearchClass.class);
BankEntity bank = Mockito.mock(BankEntity.class);
// 'findAddressFromGeoLocation' and 'getGeo_location' to be mocked. They are called within 'target' method
when(searchClass.findAddressFromGeoLocation(anyString())).thenReturn(Address);
when(bank.getGeo_location()).thenReturn(spatialLocation2);
// 'writeResultInJson' is void method. so needed to 'spy' 'SearchClass'
SearchClass spy = Mockito.spy(SearchClass.class);
Mockito.doNothing().when(spy).writeResultInJson(anyObject(), anyString());
//This is test target method called. **Issue is control is not going into this method**
SearchedBanksEntity searchBanksEntity = searchClass.findNearbyBanksByGeoLocation(spatialLocation, 500);
assertNull(searchBankEntity);
}
What i have tried is also calling the real method on it,
Mockito.when(searchClass.findNearbyBanksByGeoLocation(anyString(), anyDouble())).thenCallRealMethod();
This calls real method but the methods i mocked above, are executing like real one. Means 'mocked methods' are not returning what i asked them to return.
So, what wrong i am doing here ?
why method is not executing?
The method is not getting called because you are calling it on a mock. You should call the method on an actual object.
Or you could use something like this before invoking the method.
Mockito.when(searchClass.findNearbyBanksByGeoLocation(Mockito.eq(spatialLocation), Mockito.eq(500))).thenCallRealMethod();
But I think this is not the way you should write the test. You shouldn't be mocking SearchClass in the first place. Instead there would be a dependency in SearchClass which gets you the address and geo location. You should be mocking that particular dependency.
OK, let's say we have this code:
class Foo {
// has a setter
SomeThing someThing;
int bar(int a) {
return someThing.compute(a + 3);
}
}
We want to test Foo#bar(), but there's a dependency to SomeThing, we can then use a mock:
#RunWith(MockitoJunitRunner.class)
class FooTest {
#Mock // Same as "someThing = Mockito.mock(SomeThing.class)"
private SomeThing someThing,
private final Foo foo;
#Before
public void setup() throws Exception {
foo = new Foo(); // our instance of Foo we will be testing
foo.setSomeThing(someThing); // we "inject" our mocked SomeThing
}
#Test
public void testFoo() throws Exception {
when(someThing.compute(anyInt()).thenReturn(2); // we define some behavior
assertEquals(2, foo.bar(5)); // test assertion
verify(someThing).compute(7); // verify behavior.
}
}
Using a mock we are able to avoid using a real SomeThing.
Some reading:
http://www.vogella.com/tutorials/Mockito/article.html
https://github.com/mockito/mockito/wiki

Unit testing that log message written when exception caught

Here is the code that I am working with. In this test I want to verify that the log method is being called when an exception is caught.
public class SuperClass(){
public void log()
{
do some logging;
}
}
public class ClassUnderTest extends SuperClass(){
public String methodbeingtested(Object param)
{
try
{
String a = SomeObject.
methodthatthrowsexception(param);//static method, throws JAXB/NPE
}
catch(Exception exp)
{
log("log msg",exp);//inherited method
}
}
}
public class ClassUnderTestTest {
#Test
public testmethodbeingtested(){
ClassUnderTest cut = new ClassUnderTest()
ClassUnderTest cutspy = Mockito.spy(cut);
cutspy.methodbeingtested(param);
Mockito.verify(cutspy).log("log msg", new Exception()); // exp is needed to here.
}
}
After looking at several samples, the above was the closest I could get. This testcase forces an exception. But it fails to verify the log method call as Mockito.verify requires the exact exception (exp) that is caught, which the test case does not have access to.
Is there any other way to test this scenario?
Mockito's verify method can be used with argument matchers. If you want to verify that log was called, with any Exception at all as the second argument, you can just write
verify(cutspy).log(eq("log msg"), any(Exception.class));
I've assumed that you have the right static imports for verify, eq and any.
As an aside, this test does not need PowerMock. Your line PowerMock.expectLastCall().once(); is both redundant and confusing, and should probably be removed, along with the #PrepareForTest annotation.
Instead of spying on ClassUnderTest, you should mock the logging framework, inject it into the class and then verify that the log method gets called. Id' also mock the SomeObject class and have it throw exception.
As an aside, you should really evaluate if you need to verify your log statements. Perhaps you have a valid reason to do so but typically, asserting/verifying to this extent is not required and will only make your tests brittle.

EasyMock Exception Handling

I am creating some junit test cases using EasyMock. So far it makes sense for classes I am expecting to return POJOs, but how should I handle dealing with a DAO object that itself could throw an exception. My test case is to check for an expected exception thrown when the DAO encounters an issue. Using EasyMock I try and mock the DAO object (testing from the foo class), what is the correct way to handle the lower level DAO exception.
An example of the classes/simple calls is below: (Assume all getters/setters/constructors are valid and present)
public class foo{
private daoClass dao = daoClass.getInstance();
public String getValueFromDB(String key) throws DBException{
return dao.lookup(key);
}
}
public class daoClass{ //singleton DAO
public daoClass getInstance(){
//singleton access here
}
public String lookup(String key) throws DBException{
try{
//DB LOGIC
}
catch(Exception e){
throw new DBException(e.getMessage());
}
}
}
When I try and test the foo class, I want to be able to test for this DBException. How do I handle this, should I be surronding the DAO call in a try/catch (in the test), or add a throws to the test? I know expected=DBException will pass the test if that is thrown, but how syntactically should you handle any number of inner exceptions?
Test code Example:
#Test(expected=DBException.class)
public void testFooError(){
String key = "test";
String value = "expected";
daoClass daoMock = createMock(daoClass.class);
try{
expect(daoMock.lookup(key)).andReturn(value);
} catch (DBException e){
// ???
}
}
What is the correct way to handle when the expect could potentially throw errors? Should the test method throw the exception, or should a try/catch be used? Is it still correct to use the expected=EXCEPTION tag on the test?
Here's how I handle exceptions in unit tests:
If you aren't explicitly testing for the exception then you should add a throws clause to the method - if the exception was thrown and you weren't expecting it to be thrown then that's a test fail.
e.g.,
#Test
public void testFooNormal() throws DBException{
String key = "test";
String value = "expected";
daoClass daoMock = createMock(daoClass.class);
expect(daoMock.lookup(key)).andReturn(value);
// do an assert on returned value
...
}
If you are explicitly testing for the exception then put a try-catch around the line you expect it to be thrown from (catching the narrowest version of the Exception you expect) and then set a boolean in the catch clause and the assert should be on the value of the boolean.
e.g.,
#Test
public void testFooError(){
String key = "test";
String value = "expected";
boolean exceptionThrown = false;
daoClass daoMock = createMock(daoClass.class);
try{
expect(daoMock.lookup(key)).andReturn(value);
}catch (DBException e) {
exceptionThrown = true;
}
// assert exceptionThrown is true
...
}
This is a good way to test exceptions because it means you are testing not only that the correct exception is thrown but also that it's thrown from exactly the line you expect. If you use #test(expected=...) then a different line in the test could throw that exception and the test could incorrectly pass.
Your DAO logic should not change based on your test . If you are expecting your DAO to throw the exception then keep it that way and test the Exception in the way you are testing .
If you are catching the exception in DAO itself to do rollback or logging etc. , then the Test Case shouldn't expect Exception as it is not a test case scenario. You may check for NULL in this case as I expect your DAO will be returning NULL .

Categories

Resources