spockframework/spock — pull request #50 by Fuud (2014-10-25 13:42:34+00:00)
Title: Soft asserts: check all then throw all failures

Note: this pull-request based on #49

# Idea

Lets take an example:

```groovy
public class IntegrationTest extends Specification {
def "test1"() {
when:
def result = postRequest();
def body = result["body"] // here can be complicated extraction logic
def code = result["code"]
then:
body == "hello!"
code == 256
}

Object postRequest() {
[body: "hi", code: 42]
}
}
```

It fails with:
```
Condition not satisfied:

body == "hello!"
| |
hi false
5 differences (16% similarity)
h(i----)
h(ello!)

at IntegrationTest.test1(Testss.groovy:13)
```

It's enougth for small and fast unit tests. But for integration tests we should provide all information that we have. So it will be better to check _all_ conditions and report all failures. This behaviour should be enabled only if user explicitly enable it (because there can be blocking operations based on previous conditions). For example:
```groovy
@AssertionMode(AssertionType.CHECK_ALL_THEN_FAIL)
public class IntegrationTest extends Specification {
def "test1"() {
when:
def result = postRequest();
def body = result["body"] // here can be complicated extraction logic
def code = result["code"]
then:
body == "hello!"
code == 256
}

Object postRequest() {
[body: "hi", code: 42]
}
}
```
will be reported as
```
Condition not satisfied:

body == "hello!"
| |
hi false
5 differences (16% similarity)
h(i----)
h(ello!)

at IntegrationTest.test1(Testss.groovy:13)

Condition not satisfied:

code == 256
| |
42 false

at IntegrationTest.test1(Testss.groovy:14)
```

# Additional rules
* User can separate blocks by then-then-then chain, for example this will report only one failure:
```groovy
@AssertionMode(AssertionType.CHECK_ALL_THEN_FAIL)
public class IntegrationTest extends Specification {
def "test1"() {
when:
def result = postRequest();
def body = result["body"] // here can be complicated extraction logic
def code = result["code"]
then:
body == "hello!"
then:
code == 256
}

Object postRequest() {
[body: "hi", code: 42]
}
}
```

* AssertionMode annotation can be specified on method level to override class-level annotation (so this feature can be enabled or disabled for specific method).

# Other implementations
* JUnit has org.junit.rules.ErrorCollector rule. http://junit.org/javadoc/4.9/org/junit/rules/ErrorCollector.html
* TestNG has SoftAsserts. http://beust.com/weblog/2009/06/25/soft-asserts/