check errorcode with #rule in junit - java

I found #Rule annotation in jUnit for better handling of exception.
Is there a way to check error code ?
Currently my code looks like (without #Rule):
#Test
public void checkNullObject() {
MyClass myClass= null;
try {
MyCustomClass.get(null); // it throws custom exception when null is passed
} catch (CustomException e) { // error code is error.reason.null
Assert.assertSame("error.reason.null", e.getInformationCode());
}
}
But with use of #Rule, I am doing following :
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void checkNullObject() throws CustomException {
exception.expect(CustomException .class);
exception.expectMessage("Input object is null.");
MyClass myClass= null;
MyCustomClass.get(null);
}
But, I want to do something like below:
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void checkNullObject() throws CustomException {
exception.expect(CustomException .class);
//currently below line is not legal. But I need to check errorcode.
exception.errorCode("error.reason.null");
MyClass myClass= null;
MyCustomClass.get(null);
}

You can use a custom matcher on the rule with the expect(Matcher<?> matcher) method.
For example:
public class ErrorCodeMatcher extends BaseMatcher<CustomException> {
private final String expectedCode;
public ErrorCodeMatcher(String expectedCode) {
this.expectedCode = expectedCode;
}
#Override
public boolean matches(Object item) {
CustomException e = (CustomException)item;
return expectedCode.equals(e.getInformationCode());
}
}
and in the test:
exception.expect(new ErrorCodeMatcher("error.reason.null"));

You can also see how the expect(Matcher<?> matcher) has been used within ExpectedException.java source
private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
return new TypeSafeMatcher<Throwable>() {
#Override
public boolean matchesSafely(Throwable item) {
return matcher.matches(item.getMessage());
}
};
}
public void expectMessage(Matcher<String> matcher) {
expect(hasMessage(matcher));
}

Related

How to create a custom "ExpectedException" junit rule?

I need to create a Rule to check for exceptions with customized messages. Below is my attempt, but this is not quite correct since I am simply using methods from the standard "ExpectedException". How to do it right?
public class CustomExpectedExceptionRule implements TestRule {
private final ExpectedException delegate = ExpectedException.none();
public static CustomExpectedExceptionRule none() {
return new CustomExpectedExceptionRule();
}
private CustomExpectedExceptionRule() {
}
public void expect(Class<? extends Throwable> type) {
delegate.expect(type);
}
public void expectMessage(String message) {
delegate.expectMessage(message);
}
#Override
public Statement apply(Statement base, Description description) {
return delegate.apply(base, description);
}
Now I'm trying something like that:
private final ExpectedException expectedException = ExpectedException.none();
private Object exception;
private String expectedMessage;
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
expectedException.expect((Class<? extends Throwable>) exception);
expectedException.expectMessage(expectedMessage);
base.evaluate();
}
};
}
public void expectedMessage(String expectedMessage) {
this.expectedMessage = expectedMessage;
}
public void expectedException(Object exception) {
this.exception = exception;
}
But this test does not work where the exception is thrown does not pass, though all fields here are passed.
How do I remake it in the correct form?
As I understand the requirement, in your tests you need to:
public class MyTest {
#Rule
ExpectedException expExc = ExpectedException.none();
#Test
public void throwsNothing() {
// "normal tests" not affected.
}
#Test
public void throwsExceptionWithSpecificTypeAndMessage() {
expExc.expect(MyCustomException.class);
expExc.expectMessage("substring, that passes test");// other matchers possible
// do something that (is expected to) raise(s)
// MyCustomException("substring, that passes test").
}
}
..where MyCustomException.class is a custom exception class (the lowest possible in inheritance hierarchy, which you want to "pass"), and substring, that passes test the (part of) the message, which you want to "pass".
Introducing a custom TestRule saves you 1 line/Test. In this simple case I would recommend you, not to implement the interface but extend ExternalResource (, see here)):
class CustomExpectedException extends ExternalResource /*implements (!) TestRule*/ {
private ExpectedException expExc = ExpectedException.none();
/* Parameterize the message and also the class, if it fits your needs,
* alternatively && additionally implement defaults/constants/more methods.*/
public void myExpect(String substr) {
expExc.expect(MyCustomException.class);
expExc.expectMessage(substr);// other matchers possible
}
}
...and then use it like:
public class MyTest {
#Rule
CustomExpectedException expExc = new CustomExpectedException();
...
#Test
public void throwsExceptionWithSpecificTypeAndMessage() {
expExc.myExpect("substring, that passes test");
// do something...
}
}
A rule-less approach(, see here) :
public class MyTest {
#Test
public void throwsExceptionWithSpecificTypeAndMessage() {
try { // !
// do something ...
// after that, fail the test:
org.junit.Assert.fail("expected exception!");
} catch (Exception exc) { // ! here i would recommend "the highest possible Exception" (in inheritance hierarchy) ...even better <code>Throwable</code>.
// this code can be moved to a (static) util method:
if (exc instanceof MyCustomException) {
// make assertions on ((MyCustomException) exc).getMessage();
} else {
org.junit.Assert.fail("UNexpected exception!");
// or rethrow:
// throw exc;
}
}
}
}

Test the error code of a custom exception with JUnit 4

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

Using jmockit to mock constructor that throws error: NoClassDefFoundError

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.

Skip test when exception occurs [duplicate]

My application have several execution modes, and in 1 mode it is normal that some of my tests will throw a concrete exception. I need to annotate this methods with something like #SkipOnFail that will set method as skipped if exception was thrown.
thanks in advance!
#Edit(for my question to be more clear)
#Test(expected=ConcreteException.class)
does not work for me because i need my tests to pass even if ConcreteException.class was not thrown(expected tag in junit will mark my test as failed if this exception won't be thrown), and to be skipped otherwise. In all other cases it should work as always.
#Solution that worked for me(junit v4.7) thx to #axtavt
#Rule
public MethodRule skipRule = new MethodRule() {
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
if(method.getAnnotation(SkipOnFail.class) == null) return base;
return new Statement() {
#Override
public void evaluate() throws Throwable {
try{
base.evaluate();
} catch (ConcreteException e) {
Assume.assumeTrue(false);
}
}
};
}
};
#Thx
I don't think that such a feature is available out of the box, but it should be pretty easy to implement with custom TestRule and Assume, something like this:
#Rule
public TestRule skipRule = new TestRule() {
public Statement apply(final Statement base, Description desc) {
if (desc.getAnnotation(SkipOnFail.class) == null) return base;
return new Statement() {
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (MyExceptoion ex) {
Assume.assumeTrue(false);
}
}
};
}
};
What about using JUnit Extensions?
The following example is taken from their Tutorial.
It provides aditional annotations for Prerequisites (#Prerequisite): Ignore tests based on conditions.
The required approach would be to check this during running tests. So you can simply add a #Prerequisite(requires="") annotation.
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable")
#Test public void fillData() {
// ...
}
public boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable;
}
}
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable")
#Test public void fillData() {
// ...
}
public boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable ;
}
}
This specified methods with #Prerequisite(requires = "databaseIsAvailable") must be a public method, returning a boolean or Boolean value.
If these methods will be consolidated in helper classes, you can also specify static methods within a class to be called using #Prerequisite(requires = "databaseIsAvailable", callee="DBHelper").
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable", callee="DBHelper")
#Test public void fillData() {
// ...
}
}
public class DBHelper {
public static boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable ;
}
}
Also using the Assume class (since jUnit 4.4), you can use assumeNoException():
try{
base.evaluate();
} catch (ConcreteException e) {
Assume.assumeNoException("Concrete exception: skipping test", e);
}
I searched for the docs about JUnit and it appears that from version 4.9 they have introduced what they call test rules (see TestRule). You may start from this.
The ExpectedException class marked as #Rule could be of some help in order to check for exceptions thrown but not mandatory for the test to pass.
For more advanced usage I cannot say for the moment as I've just discovered it.

ThreadWeaver always throws IllegalArgumentException

I am trying to use Google ThreadWeaver to write a unit test for concurrent code. No matter what I do, I will get an IllegalArgumentException. I am still working with an example, but even that does not work. This is what I tried:
public class ExampleTest {
public static class ExampleMain implements MainRunnable<Example> {
private Example example;
#Override
public Class<Example> getClassUnderTest() {
return Example.class;
}
#Override
public String getMethodName() {
return null;
}
#Override
public Method getMethod() throws NoSuchMethodException {
return null;
}
#Override
public void initialize() throws Exception {
example = new Example();
}
#Override
public Example getMainObject() {
return example;
}
#Override
public void terminate() throws Exception {
}
#Override
public void run() throws Exception {
example.test("second");
}
}
public static class ExampleSecondary implements SecondaryRunnable<Example, ExampleMain> {
private ExampleMain exampleMain;
#Override
public void initialize(ExampleMain main) throws Exception {
exampleMain = main;
}
#Override
public void terminate() throws Exception {
}
#Override
public boolean canBlock() {
return false;
}
#Override
public void run() throws Exception {
exampleMain.getMainObject().test("main");
}
}
public static class Example {
private List<String> list = new ArrayList<String>();
public String test(String s) {
System.out.println("1" + s);
list.add(s);
System.out.println("2" + s);
return list.get(0);
}
}
#Test
public void testThreadWeaver() throws Exception {
ClassInstrumentation instrumentation = Instrumentation.getClassInstrumentation(Example.class);
Method tested = Example.class.getDeclaredMethod("test", String.class);
Method breakpoint = List.class.getDeclaredMethod("add", Object.class);
CodePosition codePosition = instrumentation.afterCall(tested, breakpoint);
InterleavedRunner.interleave(new ExampleMain(), new ExampleSecondary(), Arrays.asList(codePosition)).throwExceptionsIfAny();
}
}
The stack trace says:
java.lang.IllegalArgumentException: Class Example is not instrumented
at
com.google.testing.threadtester.CallLoggerFactory.getClassInstrumentation(CallLoggerFactory.java:108)
at
com.google.testing.threadtester.Instrumentation.getClassInstrumentation(Instrumentation.java:65)
at MyTest.testThreadWeaver(MyTest.java:92
I followed the instructions at the official Google code webpage, but it does not seem to work. Any ideas?
ThreadWeaver needs to instrument your classes in order to add breakpoints to your methods. Therefore, you cannot run the tests with JUnit directly but you must run your test from a specific test runner. For your case this would be ThreadedTestRunner. The actual test methods must then be annotated with #ThreadedTest instead of #Test. This should work:
#Test
public void startTest() throws Exception {
new ThreadedTestRunner().runTests(getClass(), Example.class);
}
#ThreadedTest
public void testThreadWeaver() throws Exception {
// here comes your test
}

Categories