14

I'd like to create @Rule to be able to do something like this

@Test public void testValidationDefault(int i) throws Throwable {..}

Where i is parameter passed to the test by @Rule.

However I do get

java.lang.Exception: Method testValidationDefault should have no parameters

is there any way to bypass it and set the i parameter in the @Rule?

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
IAdapter
  • 62,595
  • 73
  • 179
  • 242
  • 1
    Is `@Rule` a JUnit provided annotation? Where is it supposed to be put? – Abhinav Sarkar Jun 17 '10 at 10:12
  • FYI - I was using junit,hamcrest and junitparams jar files. I forgot to use this code `@RunWith(JUnitParamsRunner.class)` before my test class name. Then, I got the error you got - `java.lang.Exception: Method testMethod should have no parameters`. – Erran Morad Oct 06 '14 at 01:19

5 Answers5

12

As IAdapter said you can't pass an argument using Rules, but you can do something similar.

Implement a Rule that holds all your parameter values and evaluates the test once for every parameter value and offers the values through a method, so the test can pull them from the rule.

Consider a Rule like this (pseudo code):

public class ParameterRule implements MethodRule{
    private int parameterIndex = 0;
    private List<String> parameters;
    public ParameterRule(List<String> someParameters){ 
        parameters = someParameters;
    }

    public String getParameter(){
        return parameters.get(parameterIndex);
    }

    public Statement apply(Statement st, ...){
        return new Statement{
             public void evaluate(){
                 for (int i = 0; i < parameters.size(); i++){
                     int parameterIndex = i;
                     st.evaluate()
                 }      
             }
        }
    }
}

You should be able to use this in a Test like this:

 public classs SomeTest{
     @Rule ParameterRule rule = new ParameterRule(ArrayList<String>("a","b","c"));

     public void someTest(){
         String s = rule.getParameter()

         // do some test based on s
     }
 }
pinkpanther
  • 4,770
  • 2
  • 38
  • 62
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
8

I use @Parameters and @RunWith(value = Parameterized.class) for passing values to tests. An example can be found here.

I did not know about the @Rule annotation, but after reading this post, I think it serves another purpose than passing parameters to the tests:

If in your test class, you create a field pointing to an object implementing the MethodRule interface, and you mark this to be processed as a rule, by adding the @Rule implementation, then JUnit will call back on your instance for every test it will run, allowing you to add additional behavior around your test execution.

I hope this helps.

MarcoS
  • 13,386
  • 7
  • 42
  • 63
1

recently i started zohhak project. it lets you write tests with parameters (but it's a runner, not a rule):

@TestWith({
   "25 USD, 7",
   "38 GBP, 2",
   "null,   0"
})
public void testMethod(Money money, int anotherParameter) {
   ...
}
piotrek
  • 13,982
  • 13
  • 79
  • 165
0

It should be noted that it is no longer true that you can't pass parameters directly to a test method. It can now be done using Theories and @DataPoints/@DataPoint.

For example:

@RunWith(Theories.class)
public class TestDataPoints {

    @DataPoints
    public static int [] data() {
        return new int [] {2, 3, 5, 7};
    }

    public int add(int a, int b) {
        return a + b;
    }

    @Theory
    public void testTheory(int a, int b) {
        System.out.println(String.format("a=%d, b=%d", a, b));
        assertEquals(a+b, add(a, b));
    }
}

Output:

a=2, b=2
a=2, b=3
a=2, b=5
a=2, b=7
a=3, b=2
a=3, b=3
a=3, b=5
a=3, b=7
a=5, b=2
a=5, b=3
a=5, b=5
a=5, b=7
a=7, b=2
a=7, b=3
a=7, b=5
a=7, b=7

With the test passing.

David H. Clements
  • 3,590
  • 2
  • 24
  • 26
  • This doesn't allow to have several DataPoints, so this functionality is pretty useless in 99% of cases. – Stanislav Bashkyrtsev Mar 21 '12 at 14:32
  • You can have multiple `@DataPoints`. If they are of different types then they get handled automatically, if they are of the same type you can use a [parameter supplier](http://blog.schauderhaft.de/2010/02/07/junit-theories/). Slightly cumbersome to set up, but relatively straightforward to use once you do so. – David H. Clements Mar 21 '12 at 22:01
  • Still much more complicated and cumbersome than DataProviders in TestNG. Though it looks to be pretty obvious that this feature is very helpful.. – Stanislav Bashkyrtsev Mar 22 '12 at 07:23
-4

it can't be done, you can't pass parameters to test method even using @Rule.

IAdapter
  • 62,595
  • 73
  • 179
  • 242