I am trying to test the following class:
package com.myclass;
public class MyClass {
private Map<String, String> dataMap = new HashMap<>();
public void extractInfoFromLine(String line) throws InvalidInputException {
String[] words = line.split(" ");
if (dataMap.containsKey(words[0])) {
throw new InvalidInputException();
}
dataMap.put(words[0], words[2]);
}
public void confirmInfoPresent(String name) {
// Do something
}
}
Using this TestNG class:
package com.myclass;
public class MyClassTest {
private MyClass myClass;
#DataProvider(name = "invalid-data-provider")
public Object[][] invalidDataProvider() {
return new Object[][] {
{ "A is B", "A"},
{ "A is D", "A"},
};
}
#BeforeTest()
public void setup() {
myClass = new MyClass();
}
#Test(dataProvider = "invalid-data-provider", expectedExceptions = InvalidInputException.class)
public void testExceptionalExtractValueForKey(String line, String name) throws InvalidInputException {
myClass.extractInfoFromLine(line);
myClass.confirmInfoPresent(name);
}
}
I have defined the following custom exception for this:
package com.myclass;
public class InvalidInputException extends Exception {
public InvalidInputException() {
super();
}
public InvalidInputException(String message) {
super(message);
}
public InvalidInputException(String message, Throwable cause) {
super(message, cause);
}
public InvalidInputException(Throwable cause) {
super(cause);
}
}
However, when I run this test case, I get the following error:
Expected exception com.myclass.InvalidInputException but got org.testng.TestException:
Method MyClassTest.testExceptionalExtractValueForKey(java.lang.String, java.lang.String)[pri:0, instance:com.myclass.MyClassTest#3930015a] should have thrown an exception of class com.myclass.InvalidInputException
I tried replacing my custom exception with a standard exception and still got the same result.
Can someone please help me with this?
#KarthickS, three different people gave you same answer already. I don't understand what else should be explained and how.
On the first #Test iteration dataMap is empty (dataMap.containsKey(words[0]) == false), so, the code inside "if" statement body will not be executed; which means that your exception will not be thrown.
TestNg will threat the test as failed since there is "expectedExceptions" attribute set in your #Test annotation. The second test iteration will pass since dataMap is not empty anymore (dataMap.put(words[0], words[2]) - you've added data on the first run).
Once again, TestNg doc says about "expectedExceptions": The list of exceptions that a test method is expected to throw. If no exception or a different than one on this list is thrown, this test will be marked a failure.
Related
Hello I have wrote a test cases for my logic and all these are working nicely. however, I have no idea how to test my custom exceptions. My code below;
#Component
public class PlaneFactory {
public Plane getPlane(String planeType) {
if (StringUtils.isBlank(planeType)) {
throw new PlaneTypeNotFoundException();
}
if (planeType.equalsIgnoreCase("lightJet")) {
return new LightJet();
} else if (planeType.equalsIgnoreCase("midJet")) {
return new MidJet();
}
else {
throw new InvalidPlaneTypeException();
}
my custom exceptions below;
PlaneTypeNotFoundException class below;
public class PlaneTypeNotFoundException extends RuntimeException {
private static final long serialVersionUID = 4314211343358454345L;
public PlaneTypeNotFoundException() {
super("You have not enter anything to check a plane");
}
}
InvalidPlaneTypeException below;
public class InvalidPlaneTypeException extends RuntimeException {
public InvalidPlaneTypeException() {
super("You need to enter one of following plane types : {LightJet, MidJet}");
}
}
which methods are suitable to use ? I mean in this scenario should I use assertThrows or just use expected annotations ?
for PlaneTypeNotFoundException I have tried something below which it did not work
#Test
public void testPlaneFactory_isEmptyOrNull_ThenReturnException() {
String planeType = "";
LightJet lightJet= (LightJet) planeFactory.getPlane(planeType);
assertThrows(PlaneNotFoundException.class, () -> lightJet.getType().equalsIgnoreCase(planeType), "You have not enter anything to check a plane");
}
If I follow your code correctly then the executable lambda in assertThrows() should be the code that you expect to generate the exception:
public void testPlaneFactory_isEmptyOrNull_ThenReturnException() {
assertThrows(PlaneNotFoundException.class, () -> planeFactory.getPlane(""));
}
If it does throw an exception then the test should pass.
A test for the second case would be:
void testInvalidPlaneType() {
assertThrows(InvalidPlaneTypeException.class, () -> planeFactory.getPlane("doh"));
}
I would like to test the return code of an exception. Here is my production code:
class A {
try {
something...
}
catch (Exception e)
{
throw new MyExceptionClass(INTERNAL_ERROR_CODE, e);
}
}
And the corresponding exception:
class MyExceptionClass extends ... {
private errorCode;
public MyExceptionClass(int errorCode){
this.errorCode = errorCode;
}
public getErrorCode(){
return this.errorCode;
}
}
My unit test:
public class AUnitTests{
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test (expected = MyExceptionClass.class,
public void whenRunningSomething_shouldThrowMyExceptionWithInternalErrorCode() throws Exception {
thrown.expect(MyExceptionClass.class);
??? expected return code INTERNAL_ERROR_CODE ???
something();
}
}
Simple:
#Test
public void whenSerialNumberIsEmpty_shouldThrowSerialNumberInvalid() throws Exception {
try{
whenRunningSomething_shouldThrowMyExceptionWithInternalErrorCode();
fail("should have thrown");
}
catch (MyExceptionClass e){
assertThat(e.getCode(), is(MyExceptionClass.INTERNAL_ERROR_CODE));
}
That is all you need here:
you don't want to expect that specific exception, as you want to check some properties of it
you know that you want to enter that specific catch block; thus you simply fail when the call doesn't throw
you don't need any other checking - when the method throws any other exception, JUnit will report that as error anyway
You can check for it using hamcres matchers as long as thrown.expect is overload to receive Matcher
thrown.expect(CombinableMatcher.both(
CoreMatchers.is(CoreMatchers.instanceOf(MyExceptionClass.class)))
.and(Matchers.hasProperty("errorCode", CoreMatchers.is(123))));
Note that you will need to add hamcrest matcher to your dependencies. Core matched that are included in JUnit is not enough.
Or if you don't want to use CombinableMatcher:
thrown.expect(CoreMatchers.instanceOf(MyExceptionClass.class));
thrown.expect(Matchers.hasProperty("errorCode", CoreMatchers.is(123));
Also, you don't need (expected = MyExceptionClass.class) declaration for #Test annotation
Expanding upon Sergii's answer, you can clean this up even more by writing a custom matcher.
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class CustomMatcher extends TypeSafeMatcher<CustomException> {
public static CustomMatcher hasCode(String item) {
return new CustomMatcher(item);
}
private String foundErrorCode;
private final String expectedErrorCode;
private CustomMatcher(String expectedErrorCode) {
this.expectedErrorCode = expectedErrorCode;
}
#Override
protected boolean matchesSafely(final CustomException exception) {
foundErrorCode = exception.getErrorCode();
return foundErrorCode.equalsIgnoreCase(expectedErrorCode);
}
#Override
public void describeTo(Description description) {
description.appendValue(foundErrorCode)
.appendText(" was not found instead of ")
.appendValue(expectedErrorCode);
}
}
The error code can then be checked like:
import org.junit.rules.ExpectedException;
public class MyObjTest {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void someMethodThatThrowsCustomException() {
thrown.expect(CustomException.class);
thrown.expect(CustomMatcher.hasCode("110501"));
MyObj obj = new MyObj();
obj.methodThatThrowsCustomException();
}
}
Reference: https://dzone.com/articles/testing-custom-exceptions
I am trying to write a unit test for a AWS SWF workflow. Below is the code I would like to Test
#Override
public void execute(String abc) {
new TryCatch() {
#Override
protected void doTry() throws Throwable {
Promise<SomeObject> temp = activityClient.action(abc);
again(temp, abc);
}
#Override
protected void doCatch(Throwable e) throws Throwable {
throw new RuntimeException(e);
}
};
}
#Asynchronous
public void again(Promise<SomeObject> someObject, String abc) {
// Do Something
}
My Test class is as below:
public class SomeWorkflowTest extends AbstractTestCase {
#Rule
public WorkflowTest workflowTest = new WorkflowTest();
List<String> trace;
private SomeWorkflowClientFactory workflowFactory = new SomeWorkflowClientFactoryImpl();
#Before
public void setUp() throws Exception {
trace = new ArrayList<String>();
// Register activity implementation to be used during test run
SomeActivitiesImpl activitiesImpl = new SomeActivitiesImpl() {
#Override
public SomeObject performHostRecovery(String abc) {
trace.add("ABC: " + abc);
SomeObject testObject = new SomeObject();
return testObject;
}
};
workflowTest.addActivitiesImplementation(activitiesImpl);
workflowTest.addWorkflowImplementationType(SomeWorkflowImpl.class);
}
#Test
public void testWorkflowExecutionCall() throws Throwable {
SomeWorkflowClient workflow = workflowFactory.getClient("XZY");
workflow.execute("XYZ");
List<String> expected = new ArrayList<String>();
expected.add("ABC: abc");
AsyncAssert.assertEqualsWaitFor("Wrong Wrong", expected, trace, null);
}
}
I have used SWF Testing Docs to write above test class. However the method that I am testing (execute()) is invoking another method in same class. I am not concerned with the execution of internal method and would like to mock it out, but given the way the workflow class object is instantiated, I am not clear on how to mock the inner method.
Can someone please point out on this?
Thanks
You actually can instantiate a workflow object or any other object that workflow uses inside the test method:
#Test
public void testWorkflowExecutionCall() throws Throwable {
SomeWorkflow workflow = new SimpleWorkflow(...);
workflow.execute("XYZ");
List<String> expected = new ArrayList<String>();
expected.add("ABC: abc");
AsyncAssert.assertEqualsWaitFor("Wrong Wrong", expected, trace, null);
}
It works because WorkflowTest executes test methods in the context of a dummy test workflow. The code
SomeWorkflowClient workflow = workflowFactory.getClient("XZY");
workflow.execute("XYZ");
actually creates a child workflow in the context of this dummy workflow. But nothing prevents you from executing any async code directly without creating the child workflow.
Jmockit is very powerful, but sometimes I cannot understand what it does behind the scene, so I have a question regarding jmockit. Hopefully the more experienced programmers on here could help shine some light on this situation :)
I have the following two classes in two separate files:
public class SmallClass {
String a;
SmallClass(String arg) throws Exception {
a = arg;
}
public String getString() {
return a;
}
}
And
public class BigClass {
private static final SmallClass smallClass;
static {
try {
smallClass = new SmallClass("dummy");
} catch (Exception e) {
throw new IllegalStateException("Could not initialized", e);
}
}
public static String getString() {
return smallClass.getString();
}
}
Now, I have a class to test BigClass:
public class BigClassTest {
#Test
public void testGet() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
}
}
If I run each of these independently, then they each passes. But if I run the whole test file, then the first test fails with:
java.lang.NoClassDefFoundError: Could not initialize class BigClass
I also tried tearing down the mock after each test like this, but it doesn't help:
public class BigClassTest {
MockUp<SmallClass> smallClassMockUp;
#Test
public void testGet() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
smallClassMockUp.tearDown();
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
smallClassMockUp.tearDown();
}
}
Any help would be appreciated. Thank you in advance!
The occurrence of NoClassDefFoundError, in a case like this, is not because the class wasn't found by the JVM (it was), but because its static initialization has failed (by throwing an exception or error from the execution of a static initializer). Once this happens, the class is left in an invalid/uninitialized state and cannot be used in the same JVM instance anymore.
For reference, see the "Initialization of classes and interfaces" section in the JLS.
Also, note that the order in which tests execute is not necessarily the textual order they appear in the test class. Here, testException (the second test) runs first. So, when testGet runs, the class is invalid and the JVM throws the error.
I have a class which I would like to test with a public static method that contains some chained method calls. Assuming that an exception occurs during the chained method calls, how do I handle this effectively and make it return some specific value?
Following is the code sample of the test class.
#RunWith(PowerMockRunner.class)
#PrepareForTest({CodeWithPrivateMethod.class,CodeWithAnotherPrivateMethod.class,CodeWithYetAnotherPrivateMethod.class})
public class CodeWithPrivateMethodTest {
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = PowerMockito.spy(new CodeWithYetAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithYetAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithYetAnotherPrivateMethod);
CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);
PowerMockito.doReturn(true).when(codeWithYetAnotherPrivateMethod, "getGambling");
//PowerMockito.doReturn(codeWithYetAnotherPrivateMethod).when(codeWithAnotherPrivateMethod, "getGambleValue");
PowerMockito.spy(CodeWithPrivateMethod.class);
CodeWithPrivateMethod.startGamble();
}
}
Following is the code sample for the class under test
public class CodeWithPrivateMethod {
public static void startGamble() {
Boolean gamble = CodeWithAnotherPrivateMethod.getGambleValue()
.getGambling();
if (gamble) {
System.out.println("kaboom");
}else{
System.out.println("boom boom");
}
}
}
Following is the code sample for the class that gets called from the class under test
public class CodeWithAnotherPrivateMethod {
static CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = new CodeWithYetAnotherPrivateMethod();
public static CodeWithYetAnotherPrivateMethod getGambleValue() {
return codeWithYetAnotherPrivateMethod; //works fine
return null; // fails
}
}
Following is the code sample for the other class that gets called from the class under test
public class CodeWithYetAnotherPrivateMethod {
public Boolean getGambling() {
return false;
}
}
So Assuming I return a null value from getGambleValue() method of CodeWithAnotherPrivateMethod class, how do I handle this null value effectively in my testclass?
This is how to specify expected exceptions using Mockito:
#Test(expected = NullPointerException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
...
Before I found out about this I would do:
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
// setup omitted
try {
CodeWithPrivateMethod.startGamble();
}
catch(NullPointerException e) {
// expected
return;
}
fail("Expected NullPointerException");
}
EDIT: Testing multiple classes that call each other statically like this is a severe code smell. Unit tests should test a single class and inline static calls should be limited to utility classes.
Another comment: your example class names are very confusing. Next time please stick with Foo, Bar, Baz or Appple, Pear, Banana.
If you are not getting an NPE then I expect your mocking/spying is interfering. If you call the code under test without mocking/spying the call chain would be:
CodeWithPrivateMethod.startGamble();
->
CodeWithYetAnotherPrivateMethod value = CodeWithAnotherPrivateMethod.getGambleValue();
->
return null;
<-
value.getGambling();
<- throws NullPointerException
What exactly are you trying to find out or achieve?
EDIT: Here's how it should work with PowerMock
#RunWith(PowerMockRunner.class)
#PrepareForTest(CodeWithAnotherPrivateMethod.class)
public class CodeWithPrivateMethodTest {
#Mock
private CodeWithYetAnotherPrivateMethod yetAnotherInstance;
#Test
public final void testStartGamble() {
// SETUP
mockStatic(CodeWithAnotherPrivateMethod.class);
expect(CodeWithAnotherPrivateMethod.getGambleValue())
.andReturn(yetAnotherInstance);
Boolean gamblingValue = true;
expect(yetAnotherInstance.getGambling()).andReturn(gamblingValue);
replayAll();
// CALL
CodeWithPrivateMethod.startGamble();
// VERIFY
verifyAll();
}