Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect javadoc of the Rule running order #1149

Merged
merged 1 commit into from
Oct 3, 2016

Conversation

Jimmy-Shi
Copy link
Contributor

In the javadoc of Rule and ClassRule, it says field rules are applied before method rules. Actually, method rules are applied before field rules.

@Jimmy-Shi
Copy link
Contributor Author

Why this pull request is not getting merged for 4 months?

@marcphilipp
Copy link
Member

Sorry for the delay. I just double-checked: Field rules are applied before method rules.

Example

public class Example {

    @Rule
    public TestWatcher methodWatcher() {
        return testWatcher("method");
    }

    @Rule
    public TestWatcher fieldWatcher = testWatcher("field");

    @Test
    public void test() {
        System.out.println("test");
    }

    private static TestWatcher testWatcher(final String prefix) {
        return new TestWatcher() {
            @Override
            protected void starting(Description description) {
                System.out.println(prefix + ": starting");
            }

            @Override
            protected void finished(Description description) {
                System.out.println(prefix + ": finished");
            }
        };
    }

}

This prints:

field: starting
method: starting
test
method: finished
field: finished

Do you have an example where methods are actually applied before fields?

@kcooney
Copy link
Member

kcooney commented Jul 22, 2015

Actually, technically field rules are applied after method rules, but when a rule is applied the new rule runs "around" the existing rule chain.

@Jimmy-Shi
Copy link
Contributor Author

@marcphilipp
I run your example and check my example again. The conclusion is:

  • My Example shows that: Method rules are applied before field rules.
  • You example shows that: Statements returned by field rules' apply methods are evaluated before statements returned by method rules' apply method.

My Example:

public class MethodOrfieldFirst {
    @Rule
    public TestRule fieldRule = new MyRule("FieldRule");

    @Rule
    public TestRule methodRule() {
        return new MyRule("MethodRule");
    }

    @Test
    public void test() {
        System.out.println("Running Test");
    }

    static class MyRule implements TestRule {

        private String name;

        MyRule(String name) {
            this.name = name;
        }

        @Override
        public Statement apply(Statement base, Description description) {
            System.out.println("applying: "+ name);
            return base;
        }
    }
}

This prints:

applying: MethodRule
applying: FieldRule
Running Test

@marcphilipp
Copy link
Member

Thanks for your example. I now get what you meant. I think the original intention of the Javadoc was do describe the execution order of the Statements returned by rules. We should definitely clarify this.

How about:

Rules defined by fields will always be applied after Rules defined by methods, i.e. the Statements returned by the former will be executed around those returned by the latter.

Is that clearer? I'm not really satisfied with it and open to your suggestions.

@Jimmy-Shi
Copy link
Contributor Author

Besides exchange the word method and field, I added below comment and update the pull request:

Since almost all of the in-box org.junit.rules.TestRule implementations are adding decorators to the passed in statement, the added decorators are evaluated in a reversed order that rules are applied.

Is it better?

@kcooney
Copy link
Member

kcooney commented Jul 24, 2015

Which rules don't add decorators to the statement chain?

@Jimmy-Shi
Copy link
Contributor Author

Some Rules added in the feature.

@kcooney kcooney added the 4.13 label Jul 17, 2016
Copy link
Member

@kcooney kcooney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(doing a pass at trying to close old issues)

Let's try to get this merged.

* before Rules defined by methods.
* undefined, in general. However, Rules defined by methods will always be applied
* before Rules defined by fields.
* Since almost all of the in-box {@link org.junit.rules.TestRule} implementations are adding
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in-box rule implementations are adding decorators (in fact, all rules are decorators) so this is confusing. Can we fix it?

Copy link
Contributor Author

@Jimmy-Shi Jimmy-Shi Sep 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late response, I was on a long holiday without computers.
How about removing the word almost

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about "Since all {@link org.junit.rules.TestRule} implementations..." ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing with decorator pattern is not a requirement. We should not say "all" with out the limitation "in-box". What do you think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All rules are decorate the statement chain. Even if a given rule doesn't "look like" a decorator it is one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not get your point. I could not see any decorating in below implementation.

    static class MyRule implements TestRule {

        private String name;

        MyRule(String name) {
            this.name = name;
        }

        @Override
        public Statement apply(Statement base, Description description) {
            System.out.println("applying: "+ name);
            return base;
        }
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No one should write rules like that. The implementation of the rule should occur when the returned statement is run.

A test rule is a factory for decorators for statements. On very rare occasions, that factory might returned the passed-in statement but even then it is clearly the decorator pattern.

If you still disagree, let's drop this sentence completely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I disagree. Let's drop this sentence and take Marc Philipp's

Rules defined by fields will always be applied after Rules defined by methods, i.e. the Statements returned by the former will be executed around those returned by the latter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated ^_^

@kcooney kcooney merged commit ee44034 into junit-team:master Oct 3, 2016
@kcooney kcooney modified the milestone: 4.13 Aug 6, 2017
sebasjm pushed a commit to sebasjm/junit4 that referenced this pull request Mar 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants