Spock makes you love unit testing

1. Why write unit tests?

First of all, unit testing is to improve code coverage. Most business scenarios are covered and tested during development, so that problems can be found and solved faster, code quality can be improved, and others can be trusted to call, thus reducing the psychological burden before going online. Instead of just handing it over to the testers and having to bug it and play it back and test it again and again, which is a waste of time and emotion.

2. Why don’t you want to write unit tests?

First thought must be trouble, influence the speed of development, already 1 day to complete the work for to write unit tests May 1 day to finish, but also to mock data, cover the unit test scenarios and cases, the greater the amount of code if it is according to the approach to writing, wrote the last may be more than the actual amount business code, the most important in this era of agile is king, It does affect the mood. Do I write unit tests? I’m not writing!

2. What is Spock?

Spock is a testing and specification framework for Java and Groovy applications. What is Groovy? Groovy is an agile development language based on the Java Virtual Machine (JVM), which you can roughly interpret as Python running on the JVM.

Spock, on the other hand, is a unit testing framework with Groovy’s elegant writing style that allows you to write unit tests in Java applications using Groovy with only a few dependencies.

Need to learn a new language? Not really, you just need to learn a little bit of structure, because most of the logic is still Java, so there’s almost no learning cost, right

3. What’s the difference between Junit and common Junit?

More simple. And naturally supports mocks.

4. Use Springboot-Maven to rely on Spock

Use in Springboot depends on SpringbootTest. Here I rely on the latest version of Spock 2.0-groovy-3.0, where 2.0 stands for Spock version and 3.0 stands for Groovy version

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<! - introduce spock - >
<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-core</artifactId>
    <version>2.0 - groovy - 3.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-spring</artifactId>
    <version>2.0 - groovy - 3.0</version>
    <scope>test</scope>
</dependency>
Copy the code

You also need to rely on a unit test plug-in

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
</plugin>
Copy the code
  1. Some small examples

We need to create a Groovy file in the unit test root folder instead of the previous Java file

Create a basic unit test file, add the Spring context, inject dependencies directly, and Spock must inherit the Specification class

@SpringBootTest(classes = TestApplication.class)
@ContextConfiguration
@ActiveProfiles(profiles = "dev")
class Test extends Specification{
    @Autowired
    Service service;
}
Copy the code

Next, write a few simple unit tests. The @unroll annotation can print multiple executions individually for easy viewing

@Unroll
def "test add #a + #b = #result"() {expect: "Test"
    service.add(a,b) == result
    where: "Conditions"
    a | b | result
    1 | 2 | 3
    2 | 3 | 6
}
Copy the code

Def defines a method, and expect: defines an expected behavior, also known as calling some service here. Here I define an add function that returns their sum

The # + argument in the method name is for easy viewing when printing

Service. Add (a,b) == result

where: "Conditions"
    a | b | result
    1 | 2 | 3
    2 | 3 | 6
Copy the code

Where lists the data you need to test, and the result of the assertion. Let’s run it once

It provides a very friendly error message when the data you provide does not match the results

When we change the return value to correct

At this point, you’re ready to write unit tests, and we’ll cover a few more.

@Unroll
def "test not throw #a + #b"() {when:
       service.add(a, b)
    then: "Conditions"
       noExceptionThrown()
    where:
    a << [1.2]
    b << [2.3]}Copy the code

When then and replaces expect above by calling the specified method or function then predicate expression and a complement to the previous tag

 where:
    a << [1.2]
    b << [2.3]
Copy the code

He also writes where, so don’t worry about aligning the table, and pass without throwing an exception after executing the two data points

Otherwise, it can be judged that all exceptions are thrown

when:
service.add(a, b)
then:
e = thrown(NullPointerException)
println(e)
where:
a << [null.2]
b << [1.null]
e << [NullPointerException, NullPointerException]
Copy the code

You can also determine how much unit test execution time you can’t exceed

@Unroll
@Timeout(unit = TimeUnit.SECONDS,value = 3)
def "test timeout #a + #b"() {expect:
    service.timeOut() / / sleep for 5 seconds
}
Copy the code

    @SharedShare data in multiple methods// Execute After similar to @after
    def cleanup(){
        orderId.clear();
    }
     // Execute Before similar to @before
    def setup(){
        orderId.clear();
    }

Copy the code

This article covers only the basics, and you can find more information on Spock’s website