@@ -17,7 +17,7 @@ Means to keep the test duration as short as possible
- Profile tests and identify slow tests, packages, components and operations.
- There is a gradle scan tool to create a report of the test performance.
- Sort tests by test duration and try to reduce it (disadvantage: total test time depends on intrinsic complexity)
- Methods that are used by normal users shouldn't only tested as admin or operator
- Methods that are used by normal users shouldn't only tested as admin or operator or observer
Structure for tests
...
...
@@ -33,7 +33,7 @@ Structure for tests
- cleanup
- tests
- abstract method
- private help methods
- private helper methods
- override methods
- help classes
...
...
@@ -41,15 +41,15 @@ Structure for tests
Conventions for Tests
---------------------
The default testing framework in Grails was changed to Spock in recent versions. Spock's naming conventions are:
The default testing framework in Grails is Spock. Spock's naming conventions are:
- Unit Test SHOULD end in "Spec" and MUST extend ```Specification```.
- Integration Test should end in "IntegrationSpec" and MUST extend ```IntegrationSpec```.
- Unit Test (classes under ```test```) SHOULD end in "Spec" and MUST extend ```Specification``` and implements ```DataTest```.
- Integration Test (classes under ```integration-test```) should end in "IntegrationSpec" and MUST extend ```Specification``` and annotated with ```@Rollback``` and ``` @Integration```.
For "legacy" tests (JUnit), the development team agreed on the following naming conventions for tests:
- Unit tests (classes under ```test/unit```) SHOULD end in "UnitTests".
- Integration tests (classes under ```test/integration```) SHOULD end in "Tests".
- Unit tests (classes under ```test```) SHOULD end in "UnitTests".
- Integration tests (classes under ```integration-test```) SHOULD end in "Tests".
Unit Testing (With Fake Objects)
--------------------------------
...
...
@@ -82,16 +82,24 @@ It also provides its own mocking framework that is very easy to use. It should b
The mechanisms below are described since a lot of tests are not migrated to Spock and use at least one of those listed.
They should not be used in Spock tests, although they may be handy for complicated cases.
> **Note:** It is not possible in Spock to mock or stub (parts of) the class under test.
> The whole point of mocking is to get defined behavior of the collaborators.
> Requiring to mock parts of the class is a strong indicator of a design smell, usually a violation of the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle).
> It should be fixed by improving the design.
Spock provides the for types for mocking:
- Stub: Stub a class or interface complete. Only used for overwrite the result, no check about how often it is called.
- Mock: Mock a class or interface complete. Allow mocking only defined methods. All methods not overridden return null or 0
- Spy: Mock a class partially. Allow mocking only defined methods. Not mocked methods keep there origin functionality.
Note: Requiring to mock parts of the class is a strong indicator of a design smell, usually a violation of the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle).
It should be fixed by improving the design.
If possible avoid Spy.
- GroovyMock: Mock a class or interface with Groovy support, for example mocking dynamic added methods or static methods.
Note: Usually not needed. And should also avoided.
- GroovySpy: Mock a class partially with Groovy support, for example mocking dynamic added methods or static methods.
Note: Same as Spy: Bad design.
#### Mocking ####
Mocking is the way Spock does [Interaction Based Testing](https://spockframework.github.io/spock/docs/1.0/interaction_based_testing.html).
It allows you to check if some method you expect to be called in a collaborator is actually called (or not called at all).
Besides the number of invocations it allows to check for specific arguments and the order of method calls.
Besides, the number of invocations it allows to check for specific arguments, and the order of method calls.
Spock is a lenient mocking framework, meaning that unexpected method calls are allowed and answered with a default response in order to prevent over-specification of a test.
(Which makes test brittle.) If you explicitly want to check that no other methods were called, the documentation lists a way to do that.
...
...
@@ -109,6 +117,7 @@ or
```groovy
Subscribersubscriber=Mock()
```
Spock's term for an assertion on a mock is interaction.
An interaction is composed of a cardinality (how often a method is called) and the target and method constraint (which method on which object is called.
It can optionally have an argument constraint to check if the method was called with the correct value.
...
...
@@ -121,7 +130,7 @@ It can optionally have an argument constraint to check if the method was called
| target constraint
cardinality
```
A full example may look like the following: Two ```Subscribers``` are registred with a ```Publisher``` in order to be informed.
A full example may look like the following: Two ```Subscribers``` are registered with a ```Publisher``` in order to be informed.
If the ```Publisher``` sends a message, it is supposed to call the receive method on all of its Subscribers once.
```groovy
...
...
@@ -146,7 +155,7 @@ class PublisherSpec extends Specification {
}
```
Here, an argument constrained is used to check that the received message is equal to the input message.
If the argument is no concern, an underscore (_) can used to ignore the passed argument(s).
If the argument is no concern, an underscore (_) can be used to ignore the passed argument(s).
It is also possible to use the underscore on all other constraints.
So if you do not care on which object the ```receive()``` method was called, you could write the above test like this:
...
...
@@ -206,7 +215,8 @@ or
Subscribersubscriber=Stub()
```
> **Note:** In Spock, a stub can only be used for stubbing whereas a mock can be used for mocking and stubbing. Using a stub in the declaration shows the role of that object in the test setup and should be preferred if only stubbing is needed.
> **Note:** In Spock, a stub can only be used for stubbing whereas a mock can be used for mocking and stubbing.
> Using a stub in the declaration shows the role of that object in the test setup and should be preferred if only stubbing is needed.
A stub usually has a very limited number of interactions, so they are often declared at construction time:
The above example shows that it is possible to return different values for different invocations using an argument constraint to differentiate between the two. Calling receive() with a message "message2" will always provide the "fail" status code.
The above example shows that it is possible to return different values for different invocations using an argument constraint to differentiate between the two.
Calling receive() with a message "message2" will always provide the "fail" status code.
It is also possible to provide sequences of return values that will return the next value in the list on each following invocation. You can use the triple-arrow operator for this:
It is also possible to provide sequences of return values that will return the next value in the list on each following invocation.
This will return "ok" for the first invocation, "error" for the second and third, and "ok" for all subsequent invocations. For more advanced uses, such as computing return values based on the arguments, see the documentation.
This will return "ok" for the first invocation, "error" for the second and third, and "ok" for all subsequent invocations.
For more advanced uses, such as computing return values based on the arguments, see the documentation.
To perform side effects such as throwing an exception, use a closure:
...
...
@@ -276,6 +289,8 @@ But for a lot of times stubbing is all that is needed.
### Faking via MetaClass ###
> **Note:** This section is kept for legacy tests. It does not apply to Spock tests, as better mechanisms exist. (It can be used, though.)
Another method is using fakes by modifying the MetaClass of an object.
When used with singletons such as services, this has side effects that could break unrelated tests.
It violates the principles of isolation and is discouraged. Usually one of the other methods above are sufficient.
...
...
@@ -291,6 +306,9 @@ controller.search()
When using a Spock test the annotation ```@DirtiesRuntime``` can be used on methods that change MetaClass.
Spock will take care that the runtime is cleaned so that no side effects arise.
> **Attention:** If you change a complete class, it is necessary to clean up the changes after the test, otherwise the change stay and influence the next running test.
> Therefore we have an help method: ```TestCase.removeMetaClass```
### Faking via Inheritance ###
This is the "old-school" method of faking. In this example, the service is extended and the public methods are overridden: