Mocking Java Constant variables (public static) using Mockito/JUnit - java

I need to mock the constant variable in order to test one of my method. How can I do it with Mokito and Junit.
#Component( "mybean" )
#org.springframework.context.annotation.Scope( value="session" )
public class MyBean {
Public void methodToBeTested() {
if (!AppConst.SOME_CONST.equals(obj.getCostCode())) {
// some logic
}
}
}
AppConst class
#Configuration
public class AppConst
{
public static String SOME_CONST;
public static String HOST_URL;
#PostConstruct
public void postConstruct()
{
SOME_CONST = "My Code";
HOST_URL = "Some URL";
}
}
So, from my junit test class, how can I mock the AppConst and it's variables? Now, when I run it, i hit a nullpointer error.
Can this be done with powermock? if yes please give some sample
Mockito version I use.
compile "org.mockito:mockito-all:1.9.5"
compile "org.powermock:powermock-mockito-release-full:1.6.1"

Instead of mocking there would be another solution to be able to test it:
public void methodToBeTested(SomeObject obj) {
performLogic(AppConst.SOME_CONST, obj);
}
boolean performLogic(String check, SomeObject testObj) {
if (!check.equals(obj.getCostCode())) {
// some logic
return true;
}
return false;
}
That way you can test two things, both combined show you that your code works as intended:
public void testMethodToBeTested() {
MyBean mb = new MyBean() {
#Override
void performLogic(String check, SomeObject testObj) {
assertSame("check constant is passed", AppConst.SOME_CONST, check);
}
}
mb.methodToBeTested(new SomeObject());
mb = new MyBean();
SomeObject so = createSomeTestObject("My Code"); // not the actual constant but an equal String
assertFalse("check some logic not occurred", mb.performLogic("My Code", so));
so = createSomeTestObject("Not the constant");
assertFalse("check some logic not occurred", mb.performLogic("Not the constant", so));
assertTrue("check some logic occurred", mb.performLogic("My Code", so));
// additional tests covering the actual logic
}
Another solution could be putting the condition of the if-statement into its own method, e.g. shouldLogicOccurr(String check) and test that method individually.
In other words: Sometimes it's necessary to refactor your code to make tests easier or sometimes even possible at all. A good side effect is the next time you implement something you already have testability in mind and create your code suitable for this in the first place.
Mocking is a good way to get things under test that use third party libraries that can't be changed and have too many dependencies to be set up but if you end up using that for your own code you've got a design issue.

Related

Is it possible to initialize some of the fields in a mock object

I have a code that I cannot correctly cover with tests.
I am using the Mockito library.
And I had difficulty at the moment of starting the test.
Below is the test code:
#Test
public void testLoadCar() {
when(remoteService.loadData()).thenReturn(new DataResult<DataCar>("", "", new DataCar()));
when(dataResult.hasError()).thenReturn(true);
when(dataResult.response.hasHeaders()).thenReturn(true);
requestNetwork = new RequestNetwork(remoteService);
Response<DataCar> response = requestNetwork.load(request);
}
These are objects in the test class: remoteService, dataResult, request.
I am concerned about the moment where I am trying to implement the when method:
when(dataResult.response.hasHeaders()).thenReturn(true);
I would like to know if such a recording will work.
If it doesn't work, then how can we handle this moment:
protected Response createResponse(DataResult<T> dataResult) {
if (dataResult.hasError() || !dataResult.response.hasHeaders()) {
return dataResult.getErrorMessage());
} else {
return Response.data(dataResult.value);
}
}
This is a method on the system under test (SUT) that has a createResponse() method. This method contains a call to the mock method of the DataResult object.
To implement dataResult.hasError () I got it:
when (dataResult.hasError ()). thenReturn (true);
Then with! DataResult.response.hasHeaders () I have a problem. Since I don't understand how to substitute the value I need.
Not all objects that your object under test interacts with need to be mocks.
Remember that you can use POJOs as well.
DataResult looks like a perfect candidate for a POJO.
You gain nothing by using a mock objet if you can create a POJO with desired state and behaviour.
Looking at the posted code, it looks like it is easy to create:
new DataResult<DataCar>("", "", new DataCar())
On top of that:
Your code looks suspicious to me.
when stubbing remoteService.loadData() you create a new instance of DataResult
subsequently, you stub some calls on dataResult, which is not an object returned from remoteService.loadData()
And to answer original post:
You can set fields on mocks (directly if access modifiers allow it, or via reflection otherwise). Note that this is highly not-idiomatic and surprising use of mocks.
class A {
B b;
}
class B {
boolean hasHeaders() {
return true;
}
}
#ExtendWith(MockitoExtension.class)
public class AAATest {
#Mock
A aMock;
#Mock
B bMock;
#BeforeEach
void setupMocks() {
aMock.b = bMock;
}
#Test
void testFieldInMockIsInitialized() {
Assertions.assertEquals(bMock, aMock.b);
}
}

Mockito, verify that line not executed for some condition inside one test method

Im writing unit test using testng and mockito.
Im normally practice to call one method few times inside same test method by using different values / condition to check all scenarios.
Please dont think about the logic, and design i have provided. this is just sample for clear what actually i want to make.
Review code below.
public class Human {
private String name;
private boolean parent;
private List<Human> childs = new ArrayList<>();
public String getName() {
return name;
}
public boolean isParent() {
return parent;
}
public void setParent(boolean parent) {
this.parent = parent;
}
public void addChild(List<Human> childs) {
this.childs = childs;
}
public List<Human> getChilds() {
return childs;
}
}
public class Validator {
public boolean isParent(Human human) {
if (null == human) {
return false;
}
if (human.isParent()) {
return true;
}
if (human.getChilds().size() > 0) {
return true;
}
return false;
}
}
Im writing test case for Validator isParent method by using mockito.
public class ValidatorTest {
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
}
In here i want to verify that getChilds() never call for second method call to validator.isParent(human) because mocked human set to return true when call human.isParent();
I used Mockito.verifyZeroInteractions() but it says fail
As i understand Mockito.verifyZeroInteractions() check through all test. not only for particular method call.
I want to know is there some way to verify that method is not call for some cases and method call for same cases within same test method.
Or should i should practice test one scenario in one test method.
It's a good practice to have "one scenario per one one test method" (see How many unit tests should I write per function/method? )
Technically it's still possible to reset mocks with Mockito.reset(...), but this what official documentation says about it:
Smart Mockito users hardly use this feature because they know it could be a sign of poor tests.
Normally, you don't need to reset your mocks, just create new mocks for each test method.
Instead of reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests. First potential code smell is reset() in the middle of the test method. This probably means you're testing too much. Follow the whisper of your test methods: "Please keep us small & focused on single behavior".
See https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html#17
The verify method can accept a second argument where you can specify how many times the method has been called. You can use this to say the method was never called, called once, twice etc.
For example:
import static org.mockito.Mockito.never;
...
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human, never()).getChilds();
}
The documentation for this is here: http://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html#4
I want to point out that this question seriously abuses mocking, for testing something that can easily and cleanly be tested without any mocks.
This is what the tests should look like:
public class ValidatorTest {
final Validator sut = new Validator();
#Test
public void checkThatNoHumanIsNotAParent() {
boolean isParent = sut.isParent(null);
assertFalse(isParent);
}
#Test
public void checkHumanThatIsNotAParent() {
Human notAParent = new Human();
boolean isParent = sut.isParent(notAParent);
assertFalse(isParent);
}
#Test
public void checkParentHumanWithNoChildIsAParent() {
Human parentWithNoChildren = new Human();
parentWithNoChildren.setParent(true);
boolean isParent = sut.isParent(parentWithNoChildren);
assertTrue(isParent);
}
#Test
public void checkHumanNotMarkedAsParentButWithChildIsAParent() {
Human humanWithChildren = new Human();
Human child = new Human();
humanWithChildren.addChild(child);
boolean isParent = sut.isParent(humanWithChildren);
assertTrue(isParent);
}
}
These tests completelly exercise all four scenarios. They are clearly much better than a version that uses mocking. Finally, note that Mockito's documentation (in the page on how to write good tests) also says that value objects (such as Human) should not be mocked.

How to unit test a function that has a condition for the state of something?

I'm trying to write a unit test for a function that has a condition for wifi state. When the wifi state is disconnected, the function returns with false, but I want to simulate a scenario when the wifi state is connected. How do I go about it? Should I make a setter for the state variable? Isn't that a bad approach?
The function I want to test:
public boolean performSomething() {
if (WIFI_STATE != "connected") {
return false;
}else{
....
}
}
I want to test the else part of the function above, but as you may have guessed, the function executes the if condition, and returns false because WIFI_STATE is "disconnected"
Without seeing any of your code, make sure your class uses a WifiState constructor parameter or injection (or something similar). In your test you can then provide a mock for this object and set the state accordingly to your testing needs.
Two approaches that I can think of:
1: Define a sensor's state capturing class say WifiStatus, which your production code initializes automatically through a static initializer.
For testing, you can load a dummy WifiStatus class though a test initializer or change the value of WifiStatus through instrumentation.
2: Use WifiStatus as a interface and then mock it for dependency injection. This approach is more common.
public interface WifiStatus{
boolean isConnected();//
}
public class Performer{
WifiStatus wifiStatusProvider;
public Performer(WifiStatus stateProvider){
this.wifiStatusProvider = stateProvider;
}
public boolean performSomething() {
//if (WIFI_STATE != "connected") {
if (wifiStatusProvider.isConnected() != true) {
return false;
}else{
....
}
}
}
For test class, you use as follows:
public class PerformerTest{
#Test
public void verifyPerformSomething(){
WifiStatus dummyWifiStatus = mock(WifiStatus.class);
doReturn(true).when(dummyWifiStatus).isConnected();
new Performer(dummyWifiStatus).performSomething();
}
}
Assuming you are talking about "Local Unit Tests" and not "Instrumented Unit Tests", you can use Robolectric: http://robolectric.org
http://robolectric.org/javadoc/3.0/org/robolectric/shadows/ShadowWifiManager.html
https://github.com/robolectric/robolectric/blob/master/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java
Local Unit Tests:
https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
Instrumented Unit Tests:
https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
Well, for testing, you must be sure for your input how your output looks like because you need to compare them. Make the boolean value of wifi state is injected from outside, so you can mock it how you like. For example:
public boolean method(boolean wifiState){
return !wifiState;
}
So now you can be sure that if your parameter is false you will got true and vice versa so you can mock that param and make your tests.
Chiming in with a code-based answer based on john16384's answer. You mention that the state is set with other functions within the same class, assuming those methods are public I propose something like this (assuming WifiChecker is your class):
private WifiChecker wifiChecker;
#Before public void setUp() {
wifiChecker = new WifiChecker();
}
#Test public void testWifiConnected() {
wifiChecker.setConnected()
assertTrue(wifiChecker.performSomething());
}
#Test public void testWifiDisconnected() {
wifiChecker.setDisconnected()
assertFalse(wifiChecker.performSomething());
}

Mocking member variables of a class using Mockito

I am a newbie to development and to unit tests in particular .
I guess my requirement is pretty simple, but I am keen to know others thoughts on this.
Suppose I have two classes like so -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Let's say I am writing unit test to test First.doSecond() method. However, suppose, i want to Mock Second.doSecond() class like so. I am using Mockito to do this.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
I am seeing that the mocking does not take effect and the assertion fails.
Is there no way to mock the member variables of a class that I want to test . ?
You need to provide a way of accessing the member variables so you can pass in a mock (the most common ways would be a setter method or a constructor which takes a parameter).
If your code doesn't provide a way of doing this, it's incorrectly factored for TDD (Test Driven Development).
This is not possible if you can't change your code. But I like dependency injection and Mockito supports it:
public class First {
#Resource
Second second;
public First() {
second = new Second();
}
public String doSecond() {
return second.doSecond();
}
}
Your test:
#RunWith(MockitoJUnitRunner.class)
public class YourTest {
#Mock
Second second;
#InjectMocks
First first = new First();
public void testFirst(){
when(second.doSecond()).thenReturn("Stubbed Second");
assertEquals("Stubbed Second", first.doSecond());
}
}
This is very nice and easy.
If you look closely at your code you'll see that the second property in your test is still an instance of Second, not a mock (you don't pass the mock to first in your code).
The simplest way would be to create a setter for second in First class and pass it the mock explicitly.
Like this:
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
public void setSecond(Second second) {
this.second = second;
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
....
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
first.setSecond(sec)
assertEquals("Stubbed Second", first.doSecond());
}
Another would be to pass a Second instance as First's constructor parameter.
If you can't modify the code, I think the only option would be to use reflection:
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
Field privateField = PrivateObject.class.
getDeclaredField("second");
privateField.setAccessible(true);
privateField.set(first, sec);
assertEquals("Stubbed Second", first.doSecond());
}
But you probably can, as it's rare to do tests on code you don't control (although one can imagine a scenario where you have to test an external library cause it's author didn't :))
You can mock member variables of a Mockito Mock with ReflectionTestUtils
ReflectionTestUtils.setField(yourMock, "memberFieldName", value);
If you can't change the member variable, then the other way around this is to use powerMockit and call
Second second = mock(Second.class)
when(second.doSecond()).thenReturn("Stubbed Second");
whenNew(Second.class).withAnyArguments.thenReturn(second);
Now the problem is that ANY call to new Second will return the same mocked instance. But in your simple case this will work.
I had the same issue where a private value was not set because Mockito does not call super constructors. Here is how I augment mocking with reflection.
First, I created a TestUtils class that contains many helpful utils including these reflection methods. Reflection access is a bit wonky to implement each time. I created these methods to test code on projects that, for one reason or another, had no mocking package and I was not invited to include it.
public class TestUtils {
// get a static class value
public static Object reflectValue(Class<?> classToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = reflectField(classToReflect, fieldNameValueToFetch);
reflectField.setAccessible(true);
Object reflectValue = reflectField.get(classToReflect);
return reflectValue;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch);
}
return null;
}
// get an instance value
public static Object reflectValue(Object objToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = reflectField(objToReflect.getClass(), fieldNameValueToFetch);
Object reflectValue = reflectField.get(objToReflect);
return reflectValue;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch);
}
return null;
}
// find a field in the class tree
public static Field reflectField(Class<?> classToReflect, String fieldNameValueToFetch) {
try {
Field reflectField = null;
Class<?> classForReflect = classToReflect;
do {
try {
reflectField = classForReflect.getDeclaredField(fieldNameValueToFetch);
} catch (NoSuchFieldException e) {
classForReflect = classForReflect.getSuperclass();
}
} while (reflectField==null || classForReflect==null);
reflectField.setAccessible(true);
return reflectField;
} catch (Exception e) {
fail("Failed to reflect "+fieldNameValueToFetch +" from "+ classToReflect);
}
return null;
}
// set a value with no setter
public static void refectSetValue(Object objToReflect, String fieldNameToSet, Object valueToSet) {
try {
Field reflectField = reflectField(objToReflect.getClass(), fieldNameToSet);
reflectField.set(objToReflect, valueToSet);
} catch (Exception e) {
fail("Failed to reflectively set "+ fieldNameToSet +"="+ valueToSet);
}
}
}
Then I can test the class with a private variable like this. This is useful for mocking deep in class trees that you have no control as well.
#Test
public void testWithRectiveMock() throws Exception {
// mock the base class using Mockito
ClassToMock mock = Mockito.mock(ClassToMock.class);
TestUtils.refectSetValue(mock, "privateVariable", "newValue");
// and this does not prevent normal mocking
Mockito.when(mock.somthingElse()).thenReturn("anotherThing");
// ... then do your asserts
}
I modified my code from my actual project here, in page. There could be a compile issue or two. I think you get the general idea. Feel free to grab the code and use it if you find it useful.
If you want an alternative to ReflectionTestUtils from Spring in mockito, use
Whitebox.setInternalState(first, "second", sec);
Lots of others have already advised you to rethink your code to make it more testable - good advice and usually simpler than what I'm about to suggest.
If you can't change the code to make it more testable, PowerMock: https://code.google.com/p/powermock/
PowerMock extends Mockito (so you don't have to learn a new mock framework), providing additional functionality. This includes the ability to have a constructor return a mock. Powerful, but a little complicated - so use it judiciously.
You use a different Mock runner. And you need to prepare the class that is going to invoke the constructor. (Note that this is a common gotcha - prepare the class that calls the constructor, not the constructed class)
#RunWith(PowerMockRunner.class)
#PrepareForTest({First.class})
Then in your test set-up, you can use the whenNew method to have the constructor return a mock
whenNew(Second.class).withAnyArguments().thenReturn(mock(Second.class));
Yes, this can be done, as the following test shows (written with the JMockit mocking API, which I develop):
#Test
public void testFirst(#Mocked final Second sec) {
new NonStrictExpectations() {{ sec.doSecond(); result = "Stubbed Second"; }};
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
With Mockito, however, such a test cannot be written. This is due to the way mocking is implemented in Mockito, where a subclass of the class to be mocked is created; only instances of this "mock" subclass can have mocked behavior, so you need to have the tested code use them instead of any other instance.

Mark unit test as an expected failure in JUnit

How can I mark a test as an expected failure in JUnit 4?
In this case I want to continue to run this test until something is patched upstream. Ignoring the test goes a little too far, as then I might forget about it. I may be able to add an #expected annotation and catch the exception thrown by assertThat, but that also seems to lie about the expected behavior.
Here's what my current test looks like:
#Test
public void unmarshalledDocumentHasExpectedValue()
{
doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));
final ST title = doc.getTitle();
assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
That assert should succeed, but because of an upstream bug it doesn't. Yet, that test is correct; it should succeed. Virtually all the alternatives that I've found are misleading. Right now I think #Ignore("This test should pass once fixed upstream") is my best bet, but I still have to remember to come back to it. I'd prefer that the test run.
In Python I can use the expectedFailure decorator:
class ExpectedFailureTestCase(unittest.TestCase):
#unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
With Qt's QTestLib in C++, you can use QEXPECT_FAIL:
QEXPECT_FAIL("", "Will be fixed next version", Continue);
QCOMPARE(i, 42);
In both cases above, the unit test runs which is what I'm hoping to have happen. Am I missing something in JUnit?
I'm not quite getting the specifics of your scenario, but here's how I generally test for expected failure:
The slick new way:
#Test(expected=NullPointerException.class)
public void expectedFailure() {
Object o = null;
o.toString();
}
for older versions of JUnit:
public void testExpectedFailure() {
try {
Object o = null;
o.toString();
fail("shouldn't get here");
}
catch (NullPointerException e) {
// expected
}
}
If you have a bunch of things that you want to ensure throw an exception, you may also want to use this second technique inside a loop rather than creating a separate test method for each case. If you were just to loop through a bunch of cases in a single method using expected, the first one to throw an exception would end the test, and the subsequent cases wouldn't get checked.
What about explicitly expecting an AssertionError?
#Test(expected = AssertionError.class)
public void unmarshalledDocumentHasExpectedValue() {
// ...
}
If you're reasonably confident that only the JUnit machinery within the test would raise AssertionError, this seems as self-documenting as anything.
You'd still run the risk of forgetting about such a test. I wouldn't let such tests into version control for long, if ever.
I'm assuming here that you want the test to pass if your assert fails, but if the assert succeeds, then the test should pass as well.
The easiest way to do this is to use a TestRule. TestRule gives the opportunity to execute code before and after a test method is run. Here is an example:
public class ExpectedFailureTest {
public class ExpectedFailure implements TestRule {
public Statement apply(Statement base, Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable e) {
if (description.getAnnotation(Deprecated.class) != null) {
// you can do whatever you like here.
System.err.println("test failed, but that's ok:");
} else {
throw e;
}
}
}
};
}
}
#Rule public ExpectedFailure expectedFailure = new ExpectedFailure();
// actually fails, but we catch the exception and make the test pass.
#Deprecated
#Test public void testExpectedFailure() {
Object o = null;
o.equals("foo");
}
// fails
#Test public void testExpectedFailure2() {
Object o = null;
o.equals("foo");
}
}
First, note that the first method is marked as #Deprecated. I'm using this as a marker for the method for which I want to ignore any assertion failures. You can do whatever you like to identify the methods, this is just an example.
Next, in the ExpectedFailure#apply(), when I do the base.evaluate(), I'm catching any Throwable (which includes AssertionError) and if the method is marked with the annotation #Deprecated, I ignore the error. You can perform whatever logic you like to decide whether you should ignore the error or not, based on version number, some text, etc. You can also pass a dynamically determined flag into ExpectedFailure to allow it to fail for certain version numbers:
public void unmarshalledDocumentHasExpectedValue() {
doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));
expectedFailure.setExpectedFailure(doc.getVersionNumber() < 3000);
final ST title = doc.getTitle();
assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
For further examples, see ExternalResource, and ExpectedException
Ignoring an expected failure test rather than passing it
If you want to mark you tests as Ignored rather than Success, it becomes a bit more complex, because tests are ignored before they are executed, so you have to retrospectively mark a test as ignored, which would involve constructing your own Runner. To give you a start, see my answer to How to define JUnit method rule in a suite?. Or ask another question.
One option is mark the test as #Ignore and put text in there that is a bug perhaps and awaiting a fix. That way it won't run. It will then become skipped. You could also make use of the extensions to suit your need in a potentially different way.
I've taken Matthew's answer a step further and actually implemented an #Optional annotation you could use instead of the #Deprecated marker annotation he mentions in his answer. Although simple, I'll share the code with you, maybe it's of help for someone:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Optional {
/**
* Specify a Throwable, to cause a test method to succeed even if an exception
* of the specified class is thrown by the method.
*/
Class<? extends Throwable>[] exception();
}
With a simple alteration of Matt's ExpectedFailure class:
public class ExpectedFailure implements TestRule {
#Override
public Statement apply(final Statement base, final Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable e) {
// check for certain exception types
Optional annon = description.getAnnotation(Optional.class);
if (annon != null && ArrayUtils.contains(annon.exception(), e.getClass())) {
// ok
} else {
throw e;
}
}
}
};
}
}
You can now annotate your test method with #Optional and it will not fail, even if the given type of exception is raised (provide one or more types you would like the test method to pass):
public class ExpectedFailureTest {
#Rule public ExpectedFailure expectedFailure = new ExpectedFailure();
// actually fails, but we catch the exception and make the test pass.
#Optional(exception = NullPointerException.class)
#Test public void testExpectedFailure() {
Object o = null;
o.equals("foo");
}
}
[UPDATE]
You could also rewrite your tests using JUnit's org.junit.Assume instead of the tradtional org.junit.Assert, if you want your tests to pass even if the assumption does not hold.
From Assume's JavaDoc:
A set of methods useful for stating assumptions about the conditions in which a test is meaningful.A failed assumption does not mean the code is broken, but that the test provides no useful information. The default JUnit runner treats tests with failing assumptions as ignored.
Assume is available since JUnit 4.4
Use mocked upstream class if possible. Stub it with correct result. Optionally, replace mock with real object after bug is fixed.

Categories