I have some code written in Java that uses Generics. This is a simple version:
// In Java
public interface Testable {
void test();
}
public class TestableImpl implements Testable {
#Override
public void test(){
System.out.println("hello");
}
}
public class Test {
public <T extends Testable> void runTest(Collection<T> ts){
System.out.println("Collection<T>");
for(T t: ts)
t.test();
}
public void runTest(Object o){
System.out.println("Object");
System.out.println(o);
}
}
// in Groovy - this is how I have to use the code
Test test = new Test()
test.runTest([new TestableImpl(), new TestableImpl()])
test.runTest([1,2,3]) //exception here
I am suprised that the second method call is dispatched to the wrong method (wrong in my Javish understanding). Instead calling the Object overload, the Collection gets called.
I am using Groovy 2.1.9, Windows 7.
And the exception is:
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException:
Cannot cast object '1' with class 'java.lang.Integer' to class 'Testable'
org.codehaus.groovy.runtime.typehandling.GroovyCastException:
Cannot cast object '1' with class 'java.lang.Integer' to class 'Testable'
Why? How to solve this?
How to make Groovy call the same method as Java would?
edit: to further explain the case, I'd like to write a Spock test for it (just imagine the method returns something, say a String..):
def "good dispatch"(in,out) {
expect:
test.runTest(in) == out
where:
in | out
new Object() | "a value for Object"
new Integer(123) | "a value for Object"
[1,2,3] | "a value for Object"
[new TestableImpl()] | "a value for Testable Collection"
}
Others have suggested possible ways to solve your problem but here is WHY it happens.
Groovy - being a dynamic language - uses the runtime type information to invoke the correct method. Java, on the other hand, determines which method will be used based on the static type.
A simple example that demonstrates the differences between JAVA and GROOVY:
void foo(Collection coll) {
System.out.println("coll")
}
void foo(Object obj) {
System.out.println("obj")
}
In GROOVY:
Object x = [1,2,3] //dynamic type at invocation time will be ArrayList
foo(x)
//OUT: coll
In JAVA:
Object x = Arrays.asList(1,2,3);
foo(x);
//OUT: obj
Collection x = Arrays.asList(1,2,3);
foo(x);
//OUT: coll
Now in your example (it does not really have anything to do with the use of generics):
test.runTest([new TestableImpl(), ...]) //ArrayList --> collection method will be used
test.runTest([1,2,3]) //also ArrayList --> best match is the collection variant
If multiple dispatch is not what you want, can you cast the argument in the test script?
test.runTest( (Object) [1,2,3] )
This happens because Java strips the generic information from the code at compile time.
When Groovy tried to select the correct method at runtime, it gets an ArrayList as parameter for the second call (note: No generic information anymore) which matches runTest(Collection tx) better than runTest(Object o).
There are two ways to solve this:
Create two methods with different names
Delete runTest(Collection). Instead use instanceof in runTest(Object) to determine whether the argument is a collection of the correct type and delegate to a new internal method runTestsInCollection().
Lets start from the solution:
import groovy.transform.CompileStatic
import spock.lang.Specification
import spock.lang.Subject
class TestSpec extends Specification {
#Subject
Test test = new Test()
def 'Invokes proper method from JAVA class'() {
given:
List input = [1,2,3]
when:
invokeTestedMethodJavaWay(test, input)
then:
noExceptionThrown()
}
#CompileStatic
void invokeTestedMethodJavaWay(Test test, Object input) {
test.runTest(input)
}
}
First of all, you cannot override methods by generic type even in JAVA. For example if you try adding another method with same contract but overloaded with different generic type, let say public <P extends Printable> void runTest(Collection<P> ps) you will run into disambiguation problem as both methods will have same erasure.
What's more important in your question, has been already stated in other answers here. Your expectations didn't meet the behaviour as we are getting into compile vs runtime types evaluation between respectively JAVA and Groovy. This can be very useful if one is aware of this. For example when handling exceptions. Consider following example.
JAVA:
public void someMethod() {
try {
// some code possibly throwing different exceptions
} catch (SQLException e) {
// SQL handle
} catch (IllegalStateException e) {
// illegal state handle
} catch (RuntimeException e) {
// runtime handle
} catch (Exception e) {
// common handle
}
}
Groovy:
void someMethod() {
try {
// some code possibly throwing different exceptions
} catch (Exception e) {
handle(e)
}
}
void handle(Exception e) { /* common handle */ }
void handle(IllegalStateException e) { /* illegal state handle */ }
void handle(RuntimeException e) { /* runtime handle */ }
void handle(SQLException e) { /* SQL handle */ }
I find Groovy way much cleaner than nasty try-catch multi block, especially that you can implement all handle methods in separate object and delegate handling. So it's not a bug, it's a feature :)
Getting back to the solution. You cannot annotate whole Spock's test class with #CompileStatic as you already know. However you can do this with a single method (or separate helper class). This will bring back expected java-like behaviour (compile time type evaluation) for any call from within annotated method.
Hope this helped, cheers!
PS. #Subject annotation is only used for the sake of readability. It points which object is under test (is subject of the specification).
EDIT:
After some discussion with the author of the question, not so clean but working solution:
import groovy.transform.CompileStatic
import spock.lang.Specification
import spock.lang.Subject
class TestSpec extends Specification {
#Subject Test test = new Test()
TestInvoker invoker = new TestInvoker(test)
def 'Invokes proper method from JAVA class'() {
when:
invoker.invokeTestedMethod(input)
then:
noExceptionThrown()
where:
input << [
[1, 2, 3, 4, 5],
[new TestableImpl(), new TestableImpl()]
]
}
}
#CompileStatic
class TestInvoker {
Test target
TestInvoker(Test target) {
this.target = target
}
void invokeTestedMethod(Object input) {
target.runTest(input)
}
void invokeTestedMethod(Collection input) {
if (input.first() instanceof Testable) {
target.runTest(input)
} else {
this.invokeTestedMethod((Object) input)
}
}
}
If you would need to check by more than one generic type of collection, please notice that instanceof can be used in switch case statements in Groovy.
Related
I'm essentially asking the same as this old question, but for Java 14 instead of Java 8. To spare answerers the trouble of navigating to the old question, I'll rephrase it here.
I want to get the name of a function from a referenced method. The following Java code should give you the idea:
public class Main
{
public static void main(String[] args)
{
printMethodName(Main::main);
}
private static void printMethodName(Consumer<String[]> theFunc)
{
String funcName = // somehow get name from theFunc
System.out.println(funcName)
}
}
The equivalent in C# would be:
public class Main
{
public static void Main()
{
var method = Main.Main;
PrintMethodName(method)
}
private static void PrintMethodName(Action action)
{
Console.WriteLine(action.GetMethodInfo().Name);
}
}
According to the accepted answer of the old question, this was not possible in Java 8 without considerable work, such as this solution. Is there a more elegant solution in Java 14?
Getting a method info from a method reference never was a goal on the JDK developer’s side, so no effort was made to change the situation.
However, the approach shown in your link can be simplified. Instead of serializing the information, patching the serialized data, and restoring the information using a replacement object, you can simply intercept the original SerializedLambda object while serializing.
E.g.
public class GetSerializedLambda extends ObjectOutputStream {
public static void main(String[] args) { // example case
var lambda = (Consumer<String[]>&Serializable)GetSerializedLambda::main;
SerializedLambda sl = GetSerializedLambda.get(lambda);
System.out.println(sl.getImplClass() + " " + sl.getImplMethodName());
}
private SerializedLambda info;
GetSerializedLambda() throws IOException {
super(OutputStream.nullOutputStream());
super.enableReplaceObject(true);
}
#Override protected Object replaceObject(Object obj) throws IOException {
if(obj instanceof SerializedLambda) {
info = (SerializedLambda)obj;
obj = null;
}
return obj;
}
public static SerializedLambda get(Object obj) {
try {
GetSerializedLambda getter = new GetSerializedLambda();
getter.writeObject(obj);
return getter.info;
} catch(IOException ex) {
throw new IllegalArgumentException("not a serializable lambda", ex);
}
}
}
which will print GetSerializedLambda main. The only newer feature used here, is the OutputStream.nullOutputStream() to drop the written information immediately. Prior to JDK 11, you could write into a ByteArrayOutputStream and drop the information after the operation which is only slightly less efficient. The example also using var, but this is irrelevant to the actual operation of getting the method information.
The limitations are the same as in JDK 8. It requires a serializable method reference. Further, there is no guaranty that the implementation will map to a method directly. E.g., if you change the example’s declaration to public static void main(String... args), it will print something like lambda$1 when being compiled with Eclipse. When also changing the next line to var lambda = (Consumer<String>&Serializable)GetSerializedLambda::main;, the code will always print a synthetic method name, as using a helper method is unavoidable. But in case of javac, the name is rather something like lambda$main$f23f6912$1 instead of Eclipse’s lambda$1.
In other words, you can expect encountering surprising implementation details. Do not write applications relying on the availability of such information.
I am writing a unit test for my below code
public class Class1 {
protected void execute(String a, String b) {
try{
process(a,b);
}
catch(Exception E){
Class2.write(e,Class1.class.getSimpleName())
}
}
private void process(String a, String b) {
validate(a,b);
// Doing some processing on a and b values
}
private void validate (String a, String b) {
if(a==null || a.isEmpty() || b==null || b.isEmpty())
throw new IllegalArgumentException("Input value cannot be null or empty");
}
}
For the above code, I am trying to write a UT which covers the exception use case. Below is my UT code,
#Test
public void test1(){
try {
PowerMockito.mockStatic(Class2.class);
PowerMockito.when(Class2.class, "write", Mockito.anyObject(), Mockito.anyString())
.thenCallRealMethod();
Class1 class1 = new Class1();
Class2.write(new IllegalArgumentException("Input value cannot be null or empty"),Class1.class.getSimpleClassName());
PowerMockito.verifyStatic(Class2.class, VerificationModeFactory.times(1));
class1.execute(Mockito.anyString(),Mockito.anyString());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
I am getting the below exception when I execute the above test
Argument(s) are different! Wanted:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Actual invocation has different arguments:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Can someone please help me on resolving this issue?
I really appreciate your help and time
Thanks in Advance
Your Problem:
IllegalArgumentException does not use the string message for equality. It would be safer to test the string message or the class type. I would prefer that the test detect the type rather than the message, as the string message should not be used for control flow, it is an implementation detail.
System.out.println(Objects.equals(
new IllegalArgumentException(),
new IllegalArgumentException()));
// false
System.out.println(Objects.equals(
new IllegalArgumentException().getClass(),
new IllegalArgumentException().getClass()));
// true
So to mock this I would use matchers:
any(IllegalArgumentException.class), eq(Class1.class.getSimpleName())
Issues with your design:
I'm going to end with an argument against how this code is structured, being that it is not built around dependency injection. Rather than calling the static method Class2::write, you could be calling an instance method.
For example, create the interface:
public interface Writer {
void write(Exception e, String source);
}
You can now refactor the class to provide two ctors, one that accepts any writer, and one that defaults to Class2.
public class Class1 {
private final Writer writer;
public Class1() {
this(Class2::write);
}
public Class1(Writer writer) {
this.writer = writer;
}
protected void execute(String a, String b) {
try {
process(a,b);
}
catch (Exception E) {
writer.write(e, Class1.class.getSimpleName());
}
}
...
}
Using this strategy you can now simply create an instance mock of Writer. This avoids having to mock as static method which changes the bytecode of your application, and also make your class more flexible as it can support many different writer implementations now. Anything that is modifying the bytecode of the application should be used very sparingly, such as replacing static method calls, does not truly validate the runtime execution of your code.
In my opinion, the majority of the PowerMockito/PowerMock only help verify code which was not built with testability / flexibility in mind. You shouldn't need to use anything outside of the Mockito/EasyMock tool-set for well structured code. There are some exceptions but the tool-set should be used very sparingly.
I know the simple way is to use a switch statement, but that is not what I am asking. I want to know, if I can call a method, based on its name as a String that I can modify from the user's input.
For example, I have a bunch of methods named:
func01
func02
func03
...
I want to call them using a string "func", which I modify by adding a numerical suffix to it, like 01, 02 or 03. I want call them using a few lines of code that will work for any number of methods.
Solution with Reflection
You could use Reflection to call the methods.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main {
public static void main(String args[]) throws Exception {
// Just an example calling all the methods
for (int i = 1; i < 100; i++) {
Object object = invokeMethod("func", i);
if (object != null) {
// Do something with object, cast it, etc. ...
} else {
// Error calling the methods
}
}
}
private static Object invokeMethod(String methodBaseName, int number) {
// Number format will be two digits padded by zeros,
// e.g. 01, 02, ..., 18, ...
// For three digits use "%03d" and so on or calculate
// the digits from the number itself
String methodName = methodBaseName + String.format("%02d", number);
try {
Method methodToInvoke = MethodClass.class.getMethod(methodName);
return methodToInvoke.invoke(new MethodClass());
} catch (NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// Alternatively handle this errors
return null;
}
}
}
class MethodClass {
public Object func01() {
// ...
}
// ...
public Object func99() {
// ...
}
}
Alternatively for static methods, just use:
Method method = MethodClass.class.getMethod(...);
method.invoke(MethodClass.class);
If you want to add parameters, modify the code like this:
getMethod(methodName, parameterType1.class, parameterType2.class, ...);
invoke(..., parameter1, parameter2, ...);
If you want to use a return value, just change the return type from Object to the concrete type and cast the return value from invoke to this type, e.g. Integer:
Integer result = (Integer) method.invoke(...);
Important notice
What you are trying to do is very dangerous. Reflection can be a critical harm for the security of your application. You should never allow a user to input a method name to invoke a method, otherwise he or she could potentially call any method to gain control of your application or memory. Beware of this.
You can do it using reflection. If your method is static, use the code like this:
Method method = ClassName.class.getMethod(name, param1.getClass(), param2.getClass(), ..);
method.invoke(ClassName.class, param1, param2, ..);
Or if your method isn't static, use the code like this:
Method method = object.getClass().getMethod(name, param1.getClass(), param2.getClass(), ..);
method.invoke(object, param1, param2, ..);
Reflection is a dangerous and almost impossible feature to use correctly for new Java programmers. Obtaining a method or other object-oriented element via a string is an antipattern; it breaks type safety, is very difficult to maintain and debug, and will cause you endless bugs. I speak from experience.
Instead, use a single method with overrides for each type of action you want, and let object orientation help you. If you really need a string to tell you which logic flow to use, perhaps an enum will rescue you. You can use the valueOf() method to parse the string into a valid enum, then call the desired functionality through each enum constant's implementation of an abstract method in the enum.
public class Processor
{
FOLD
{
#Override
public void process()
{
// fold logic
}
},
SPINDLE
{
#Override
public void process()
{
// spindle logic
}
},
MUTILATE
{
#Override
public void process()
{
// mutilate logic
}
},
;
abstract public void process();
}
Your client code will be similar to
Processor.valueOf(text).process();
with suitable error checking and exception handling, of course.
This is the second time I found myself writing this kind of code, and decided that there must be a more readable way to accomplish this:
My code tries to figure something out, that's not exactly well defined, or there are many ways to accomplish it. I want my code to try out several ways to figure it out, until it succeeds, or it runs out of strategies. But I haven't found a way to make this neat and readable.
My particular case: I need to find a particular type of method from an interface. It can be annotated for explicitness, but it can also be the only suitable method around (per its arguments).
So, my code currently reads like so:
Method candidateMethod = getMethodByAnnotation(clazz);
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlyMethod(clazz);
}
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
}
if (candidateMethod == null) {
throw new NoSuitableMethodFoundException(clazz);
}
There must be a better way…
Edit: The methods return a method if found, null otherwise. I could switch that to try/catch logic, but that hardly makes it more readable.
Edit2: Unfortunately, I can accept only one answer :(
To me it is readable and understandable. I'd simply extract the ugly part of the code to a separate method (following some basic principles from "Robert C.Martin: Clean Code") and add some javadoc (and apologies, if necessary) like that:
//...
try {
Method method = MethodFinder.findMethodIn(clazz);
catch (NoSuitableMethodException oops) {
// handle exception
}
and later on in MethodFinder.java
/**
* Will find the most suitable method in the given class or throw an exception if
* no such method exists (...)
*/
public static Method findMethodIn(Class<?> clazz) throws NoSuitableMethodException {
// all your effort to get a method is hidden here,
// protected with unit tests and no need for anyone to read it
// in order to understand the 'main' part of the algorithm.
}
I think for a small set of methods what you're doing is fine.
For a larger set, I might be inclined to build a Chain of Responsibility, which captures the base concept of trying a sequence of things until one works.
I don't think that this is such a bad way of doing it. It is a bit verbose, but it clearly conveys what you are doing, and is easy to change.
Still, if you want to make it more concise, you can wrap the methods getMethod* into a class which implements an interface ("IMethodFinder") or similar:
public interface IMethodFinder{
public Method findMethod(...);
}
Then you can create instances of you class, put them into a collection and loop over it:
...
Method candidateMethod;
findLoop:
for (IMethodFinder mf: myMethodFinders){
candidateMethod = mf.findMethod(clazz);
if (candidateMethod!=null){
break findLoop;
}
}
if (candidateMethod!=null){
// method found
} else {
// not found :-(
}
While arguably somewhat more complicated, this will be easier to handle if you e.g. need to do more work between calling the findMethods* methods (such as more verification that the method is appropriate), or if the list of ways to find methods is configurable at runtime...
Still, your approach is probably OK as well.
I'm sorry to say, but the method you use seems to be the widely accepted one. I see a lot of code like that in the code base of large libraries like Spring, Maven etc.
However, an alternative would be to introduce a helper interface that can convert from a given input to a given output. Something like this:
public interface Converter<I, O> {
boolean canConvert(I input);
O convert(I input);
}
and a helper method
public static <I, O> O getDataFromConverters(
final I input,
final Converter<I, O>... converters
){
O result = null;
for(final Converter<I, O> converter : converters){
if(converter.canConvert(input)){
result = converter.convert(input);
break;
}
}
return result;
}
So then you could write reusable converters that implement your logic. Each of the converters would have to implement the canConvert(input) method to decide whether it's conversion routines will be used.
Actually: what your request reminds me of is the Try.these(a,b,c) method in Prototype (Javascript).
Usage example for your case:
Let's say you have some beans that have validation methods. There are several strategies to find these validation methods. First we'll check whether this annotation is present on the type:
// retention, target etc. stripped
public #interface ValidationMethod {
String value();
}
Then we'll check whether there's a method called "validate". To make things easier I assume, that all methods define a single parameter of type Object. You may choose a different pattern. Anyway, here's sample code:
// converter using the annotation
public static final class ValidationMethodAnnotationConverter implements
Converter<Class<?>, Method>{
#Override
public boolean canConvert(final Class<?> input){
return input.isAnnotationPresent(ValidationMethod.class);
}
#Override
public Method convert(final Class<?> input){
final String methodName =
input.getAnnotation(ValidationMethod.class).value();
try{
return input.getDeclaredMethod(methodName, Object.class);
} catch(final Exception e){
throw new IllegalStateException(e);
}
}
}
// converter using the method name convention
public static class MethodNameConventionConverter implements
Converter<Class<?>, Method>{
private static final String METHOD_NAME = "validate";
#Override
public boolean canConvert(final Class<?> input){
return findMethod(input) != null;
}
private Method findMethod(final Class<?> input){
try{
return input.getDeclaredMethod(METHOD_NAME, Object.class);
} catch(final SecurityException e){
throw new IllegalStateException(e);
} catch(final NoSuchMethodException e){
return null;
}
}
#Override
public Method convert(final Class<?> input){
return findMethod(input);
}
}
// find the validation method on a class using the two above converters
public static Method findValidationMethod(final Class<?> beanClass){
return getDataFromConverters(beanClass,
new ValidationMethodAnnotationConverter(),
new MethodNameConventionConverter()
);
}
// example bean class with validation method found by annotation
#ValidationMethod("doValidate")
public class BeanA{
public void doValidate(final Object input){
}
}
// example bean class with validation method found by convention
public class BeanB{
public void validate(final Object input){
}
}
You may use Decorator Design Pattern to accomplish different ways of finding out how to find something.
public interface FindMethod
{
public Method get(Class clazz);
}
public class FindMethodByAnnotation implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByAnnotation(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByAnnotation(Class clazz)
{
return getMethodByAnnotation(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByAnnotation(clazz) : r;
}
}
public class FindMethodByOnlyMethod implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByOnlyMethod(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByOnlyMethod(Class clazz)
{
return getMethodOnlyMethod(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByOnlyMethod(clazz) : r;
}
}
Usage is quite simple
FindMethod finder = new FindMethodByOnlyMethod(new FindMethodByAnnotation(null));
finder.get(clazz);
... I could switch that to try/catch logic, but that hardly makes it more readable.
Changing the signature of the get... methods so you can use try / catch would be a really bad idea. Exceptions are expensive and should only be used for "exceptional" conditions. And as you say, the code would be less readable.
What is bothering you is the repeating pattern used for flow control--and it should bother you--but there isn't too much to be done about it in Java.
I get really annoyed at repeated code & patterns like this, so for me it would probably be worth it to extract the repeated copy & paste control code and put it in it's own method:
public Method findMethod(Class clazz)
int i=0;
Method candidateMethod = null;
while(candidateMethod == null) {
switch(i++) {
case 0:
candidateMethod = getMethodByAnnotation(clazz);
break;
case 1:
candidateMethod = getMethodByBeingOnlyMethod(clazz);
break;
case 2:
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
break;
default:
throw new NoSuitableMethodFoundException(clazz);
}
return clazz;
}
Which has the disadvantage of being unconventional and possibly more verbose, but the advantage of not having as much repeated code (less typos) and reads easier because of there being a little less clutter in the "Meat".
Besides, once the logic has been extracted into it's own class, verbose doesn't matter at all, it's clarity for reading/editing and for me this gives that (once you understand what the while loop is doing)
I do have this nasty desire to do this:
case 0: candidateMethod = getMethodByAnnotation(clazz); break;
case 1: candidateMethod = getMethodByBeingOnlyMethod(clazz); break;
case 2: candidateMethod = getMethodByBeingOnlySuitableMethod(clazz); break;
default: throw new NoSuitableMethodFoundException(clazz);
To highlight what's actually being done (in order), but in Java this is completely unacceptable--you'd actually find it common or preferred in some other languages.
PS. This would be downright elegant (damn I hate that word) in groovy:
actualMethod = getMethodByAnnotation(clazz) ?:
getMethodByBeingOnlyMethod(clazz) ?:
getMethodByBeingOnlySuitableMethod(clazz) ?:
throw new NoSuitableMethodFoundException(clazz) ;
The elvis operator rules. Note, the last line may not actually work, but it would be a trivial patch if it doesn't.
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.