I am testing using the spock framework in groovy language. I want to test TestService, and TestService uses TestRepository as below code.
@Service
@RequiredArgsConstructor
public class TestService {
private final TestRepository repository;
The test code I intended is to create the TestRepository as a mock object and put it in as a parameter, as shown below.
class SpockTest extends Specification {
private TestRepository repository = Mock()
private TestService target = new TestService(repository)
However, Spock cannot be checked during compile time even if the TestService is created and put as a parameter as shown in the code below.
class SpockTest extends Specification {
private TestRepository repository = Mock()
private TestService target = new TestService(target) // It doesn't prevent mistakes.
What I'm curious about is how Spock works, so is this possible? Or, I wonder if there is another way to prevent this mistake.
CodePudding user response:
What do you mean it doesn't prevent mistakes? If you actually run any tests it will fail with a NullPointerException
.
What you are experiencing here is one of the drawbacks of a dynamic language, you are basically passing in null
as the target
property is not initialized yet. You could try adding @CompileStatic
or @TypeChecked
, but they don't work 100% with Spock, and it is generally not advisable to do so.
You should add @NonNull
to your code to prevent null
being passed in, doing do will generate an explicit null check.
@Service
@RequiredArgsConstructor
public class TestService {
@NonNull
private final TestRepository repository;
CodePudding user response:
However, Spock cannot be checked during compile time even if the TestService is created and put as a parameter as shown in the code below.
Groovy is a dynamic language so there's no compile time for your test class but runtime only. Although it's possible to force static compilation for Groovy language, it will break your test because Spock heavily relies on the flexibility and dynamic nature of Groovy. That's why you cannot protect yourself from such errors using a compiler.
Personally, I would not recommend using Groovy and Spock for testing. I prefer to have full compiler support while developing tests. From my experience, writing unit tests in Groovy (with dynamic compilation at runtime) looks tempting at the beginning because the test code is maybe less verbose and using Spock is more readable but eventually, it will become hell when your system evolves. When you modify your code under tests and have many tests to refactor it will cost you much more effort to correct all the runtime errors caused by the modified code. You will have to perform many run-test-refactor iterations to fix all of them in comparison to using a statically compiled language. If I were you I would use statically compiled Groovy JUnit5 and get rid of Spock exactly because of the reason.