I wrote this service
public class FirstService {
private final SecondService secondService;
public FirstService(SecondService secondService) {
this.secondService = secondService;
}
public void hz() throws Exception {
try {
methodThrowsException();
} catch (Exception e){
secondService.handleErrorMessage(e.getMessage());
throw e;
}
}
private void methodThrowsException() throws Exception {
throw new Exception("message");
}
}
And this service:
public class SecondService {
public void handleErrorMessage(String message) {}
}
I need to verify that handleErrorMessage was called. I wrote a test:
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class FirstServiceTest {
private FirstService firstService;
private SecondService secondService;
#Before
public void setUp() {
secondService = mock(SecondService.class);
firstService = new FirstService(secondService);
}
#Test(expected = Exception.class)
public void hz() throws Exception {
firstService.hz();
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(secondService).handleErrorMessage(argumentCaptor.capture());
String value = argumentCaptor.getValue();
assertEquals("message", value);
}
}
Test pass. But if I change assertEquals("message666", value); it still pass. If I don't throw an exception in catch block - ArgumentCaptor captures argument, but when I throw an exception it doesn't work.
Your test is annotated:
#Test(expected = Exception.class)
This means that the test will pass if an Exception (or any subclass of) makes it up to the top level. This happens on the first line of your test:
firstService.hz();
This is why it passes. Unfortunately, that exception means that the rest of your test is never run, since that exception propagates up and out of your test method.
A bit ugly, but this snippet does what you want:
#Test
public void hz() throws Exception {
try {
firstService.hz();
// If we get here, then we didn't throw an exception - fail
Assert.fail();
} catch (Exception ex) {
// Exception was expected - disregard and continue
// no-op
}
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(secondService).handleErrorMessage(argumentCaptor.capture());
String value = argumentCaptor.getValue();
assertEquals("message", value);
}
The above runs your method, and catches the exception (and fails if you didn't get the expected exception). Then, it proceeds, and runs the rest of your test.
JUnit 5 provides a slightly cleaner way, but you'd have to migrate:
#Test
public void hz() throws Exception {
Assertions.assertThrows(Exception.class, () -> firstService.hz());
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(secondService).handleErrorMessage(argumentCaptor.capture());
String value = argumentCaptor.getValue();
assertEquals("asdf", value);
}
Related
I'm using PowerMockito to mock the private method call (privateApi) but it still makes the privateApi call which in turn makes another thirdPartCall. I'm getting into problem when thirdPartyCall throws exception. As far as I understand, if I'm mocking the privateApi, it shouldn't get into method implementation detail and return the mock response.
public class MyClient {
public void publicApi() {
System.out.println("In publicApi");
int result = 0;
try {
result = privateApi("hello", 1);
} catch (Exception e) {
Assert.fail();
}
System.out.println("result : "+result);
if (result == 20) {
throw new RuntimeException("boom");
}
}
private int privateApi(String whatever, int num) throws Exception {
System.out.println("In privateAPI");
thirdPartyCall();
int resp = 10;
return resp;
}
private void thirdPartyCall() throws Exception{
System.out.println("In thirdPartyCall");
//Actual WS call which may be down while running the test cases
}
}
Here is the test case:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClient.class)
public class MyclientTest {
#Test(expected = RuntimeException.class)
public void testPublicAPI() throws Exception {
MyClient classUnderTest = PowerMockito.spy(new MyClient());
PowerMockito.when(classUnderTest, "privateApi", anyString(), anyInt()).thenReturn(20);
classUnderTest.publicApi();
}
}
Console trace:
In privateAPI
In thirdPartyCall
In publicApi
result : 20
You just need to change the mock method call to use doReturn.
Example Partial Mocking of Private Method
Test code
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClient.class)
public class MyClientTest {
#Test(expected = RuntimeException.class)
public void testPublicAPI() throws Exception {
MyClient classUnderTest = PowerMockito.spy(new MyClient());
// Change to this
PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());
classUnderTest.publicApi();
}
}
Console trace
In publicApi
result : 20
I want my unit test classes to check for the error code (which is a custom property of my exception class) and assert when an exception is thrown from the tested code. Can I do this using testng.
I have the following exception class :
public final class CustomException extends Exception {
public CustomException(String msg,String errorCode,Throwable cause) {
super(msg,cause);
this.errorCode = errorCode;
}
private String errorCode;
public String getErrorCode() {
return this.errorCode;
}
}
My Unit Test Class :
import org.testng.annotations.Test;
public class MyUnitTestClass {
#Test(priority = 25,
expectedExceptions = CustomException.class,
expectedExceptionsMessageRegExp = "Error while doing something.")
public void testDoSomething() {
// code to invoke doSomething();
// which throws CustomException on some exception.
}
}
Instead of expectedExceptionsMessageRegExp="Error while doing something." i want to assert on an error code Eg: like "ERR100909" which will be set in the errorCode property of CustomException class.
Unit Test Framework : Testng
Version : 6.9.4
Thanks!
One of the ways in which you can do this is by implementing IHookable interface. Here's a sample that shows this in action.
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;
public class MyUnitTestClass implements IHookable {
private List<String> errorCodes = Arrays.asList("ERR100909", "ERR100");
#Override
public void run(IHookCallBack callBack, ITestResult testResult) {
callBack.runTestMethod(testResult);
Throwable t = testResult.getThrowable();
if (t != null) {
t = t.getCause();
}
boolean shouldFail = (t instanceof CustomException && errorCodes.contains(((CustomException) t).getErrorCode()));
if (!shouldFail) {
testResult.setThrowable(null);
testResult.setStatus(ITestResult.SUCCESS);
}
}
#Test
public void test1() throws CustomException {
throw new CustomException("test", "ERR100", new Throwable());
}
#Test
public void test2() throws CustomException {
throw new CustomException("test", "ERR500", new Throwable());
}
}
I'm using PowerMockito to mock the private method call (privateApi) but it still makes the privateApi call which in turn makes another thirdPartCall. I'm getting into problem when thirdPartyCall throws exception. As far as I understand, if I'm mocking the privateApi, it shouldn't get into method implementation detail and return the mock response.
public class MyClient {
public void publicApi() {
System.out.println("In publicApi");
int result = 0;
try {
result = privateApi("hello", 1);
} catch (Exception e) {
Assert.fail();
}
System.out.println("result : "+result);
if (result == 20) {
throw new RuntimeException("boom");
}
}
private int privateApi(String whatever, int num) throws Exception {
System.out.println("In privateAPI");
thirdPartyCall();
int resp = 10;
return resp;
}
private void thirdPartyCall() throws Exception{
System.out.println("In thirdPartyCall");
//Actual WS call which may be down while running the test cases
}
}
Here is the test case:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClient.class)
public class MyclientTest {
#Test(expected = RuntimeException.class)
public void testPublicAPI() throws Exception {
MyClient classUnderTest = PowerMockito.spy(new MyClient());
PowerMockito.when(classUnderTest, "privateApi", anyString(), anyInt()).thenReturn(20);
classUnderTest.publicApi();
}
}
Console trace:
In privateAPI
In thirdPartyCall
In publicApi
result : 20
You just need to change the mock method call to use doReturn.
Example Partial Mocking of Private Method
Test code
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClient.class)
public class MyClientTest {
#Test(expected = RuntimeException.class)
public void testPublicAPI() throws Exception {
MyClient classUnderTest = PowerMockito.spy(new MyClient());
// Change to this
PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());
classUnderTest.publicApi();
}
}
Console trace
In publicApi
result : 20
I am writing a test case for my class that has methods which throw exceptions (both checked and runtime). I have tried different possible ways of testing as suggested in this link.. It appears they seem to work only for runtime exceptions. for Checked exceptions, I need to do a try/catch/assert as shown in the code below. Is there any alternatives to try/catch/assert/. you will notice that testmethod2() and testmethod2_1() shows compile error but testmethod2_2() does not show compile error which uses try/catch.
class MyException extends Exception {
public MyException(String message){
super(message);
}
}
public class UsualStuff {
public void method1(int i) throws IllegalArgumentException{
if (i<0)
throw new IllegalArgumentException("value cannot be negative");
System.out.println("The positive value is " + i );
}
public void method2(int i) throws MyException {
if (i<10)
throw new MyException("value is less than 10");
System.out.println("The value is "+ i);
}
}
Test class:
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class UsualStuffTest {
private UsualStuff u;
#Before
public void setUp() throws Exception {
u = new UsualStuff();
}
#Rule
public ExpectedException exception = ExpectedException.none();
#Test(expected = IllegalArgumentException.class)
public void testMethod1() {
u.method1(-1);
}
#Test(expected = MyException.class)
public void testMethod2() {
u.method2(9);
}
#Test
public void testMethod2_1(){
exception.expect(MyException.class);
u.method2(3);
}
public void testMethod2_3(){
try {
u.method2(5);
} catch (MyException e) {
assertEquals(e.getMessage(), "value is less than 10") ;
}
}
}
#Test(expected = MyException.class)
public void testMethod2() throws MyException {
u.method2(9);
}
I would have assumed that the following test should pass, but the exception is never thrown. Any clues ?
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticService.class)
public class TestStuff {
#Test(expected = IllegalArgumentException.class)
public void testMockStatic() throws Exception {
mockStatic(StaticService.class);
doThrow(new IllegalArgumentException("Mockerror")).when(StaticService.say("hello"));
verifyStatic();
StaticService.say("hello");
}
}
It's because you are using the doThrow...when syntax incorrectly for static methods. There are a couple different ways to approach this which I've outlined in two separate test methods below.
#RunWith(PowerMockRunner.class)
#PrepareForTest({StaticService.class})
public class StaticServiceTest {
#Test (expected = IllegalArgumentException.class)
public void testMockStatic1() throws Exception {
String sayString = "hello";
mockStatic(StaticService.class);
doThrow(new IllegalArgumentException("Mockerror")).when(
StaticService.class, "say", Matchers.eq(sayString));
StaticService.say(sayString);
fail("Expected exception not thrown.");
}
#Test (expected = IllegalArgumentException.class)
public void testMockStatic2() throws Exception {
String sayString = "hello";
mockStatic(StaticService.class);
doThrow(new IllegalArgumentException("Mockerror")).when(
StaticService.class);
StaticService.say(Matchers.eq(sayString)); //Using the Matchers.eq() is
//optional in this case.
//Do NOT use verifyStatic() here. The method hasn't actually been
//invoked yet; you've only established the mock behavior. You shouldn't
//need to "verify" in this case anyway.
StaticService.say(sayString);
fail("Expected exception not thrown.");
}
}
For reference, here was the StaticService implementation I created. I don't know if it matches yours but I did verify that the tests pass.
public class StaticService {
public static void say(String arg) {
System.out.println("Say: " + arg);
}
}
See Also
http://static.javadoc.io/org.powermock/powermock-api-mockito/1.6.5/org/powermock/api/mockito/expectation/PowerMockitoStubber.html
https://github.com/jayway/powermock/wiki/MockitoUsage#how-to-stub-void-static-method-to-throw-exception
StaticServiceTest.java with imports:
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticService.class })
public class StaticServiceTest {
#Test(expected = IllegalArgumentException.class)
public void testMockStatic1() throws Exception {
/* Setup */
String sayString = "hello";
PowerMockito.mockStatic(StaticService.class);
/* Mocks */
PowerMockito.doThrow(new IllegalArgumentException("Mockerror")).when(
StaticService.class, "say", Matchers.eq(sayString));
/* Test */
StaticService.say(sayString);
/* Asserts */
fail("Expected exception not thrown.");
}
#Test(expected = IllegalArgumentException.class)
public void testMockStatic2() throws Exception {
/* Setup */
String sayString = "hello";
PowerMockito.mockStatic(StaticService.class);
/* Mocks */
PowerMockito.doThrow(new IllegalArgumentException("Mockerror")).when(
StaticService.class);
StaticService.say(Matchers.eq(sayString));
/* Test */
StaticService.say(sayString);
/* Asserts */
fail("Expected exception not thrown.");
}
}
StaticService.java
public class StaticService {
public static void say(String arg) {
System.out.println("Say: " + arg);
}
}
Tests pass fine: