-
Notifications
You must be signed in to change notification settings - Fork 5
Workshop #4: Unit and IT testing
Workshop #3 is about testing our application including the REST API we exposed. Therefore, you can find here topics such as:
- Groovy language for writing tests
- Spock test framework
- unit, integration and end-to-end testing
- mocking
- API testing in Spring
This workshop
You can find the source code that represents the status of the project after this workshop - TBA
Unit test is a type of software test where a single part of the software is verified. The purpose is to validate that each unit of the software code performs as expected. Unit tests are written by developers during the coding phase and exist along with the application code (e.g. in the separate test package, etc.). Such tests isolate the particular section of code and verify its correctness. Therefore, it is much easier to build stable applications from such tested components knowing that these parts themselves are working properly.
Integration tests (also: IT tests) verify the correctness of integration between components (that are already fully tested with unit tests). Therefore, they focus on checking if there is proper communication between them, if they are not clashing together, etc. They are also slower than unit tests because usually they need to have some application context brought up (e.g. Spring context), etc.
End-to-end tests (also: E2E tests) focus on verifying the full application workflow - from the beginning to the end. They are much heavier than integration or unit tests because they can cover several services that are communicating with each other to implement some flow.
Performance tests (also: load tests) focus on verifying if the developed application works properly under high traffic, for example. Therefore, such tests can generate fake traffic (e.g. in form of HTTP requests made to the API) and check if the application responds correctly and fast enough.
There are also other types of testing you can provide during designing the application. However, the tests mentioned above are the most common ones which you can find in almost every project.
More about different types of tests: https://www.geeksforgeeks.org/types-software-testing/
According to the official site, Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming
Groovy provides some features that make writing tests much easier and quicker.
Default imports are the imports that Groovy language provides by default. The below ones are added automatically:
import java.lang.*import java.util.*import java.io.*import java.net.*import groovy.lang.*import groovy.util.*import java.math.BigIntegerimport java.math.BigDecimal
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
Groovy is perfect for writing tests in your application thanks to its syntax and the features it provides. However, these are only words - so let's compare the sample test written in Java using JUnit5 and the same one but in Groovy using Spock (more about Spock in the next chapter).
Let's assume we have a sample component that verifies if a number is positive.
public class NumberUtils {
public static boolean isPositive(int number) {
return number > 0;
}
}The test for the isPositive(int number) method written in Java using JUnit5:
public class NumberUtilsTest {
@Test
void testIsPositive() {
assertFalse(NumberUtils.isPositive(-1));
assertFalse(NumberUtils.isPositive(0));
assertTrue(NumberUtils.isPositive(5));
}
}The same test but written in Groovy using Spock:
class NumerUtilsSpec extends Specification {
void "should test if number is positive"() {
expect:
NumberUtils.isPositive(number) == expectedResult
where:
number || expectedResult
-1 || false
0 || false
5 || true
}
}You can find more information about Groovy in the official documentation that can be found here:
https://docs.groovy-lang.org/next/html/documentation/
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯
You can find more information about Spock in the official documentation that can be found here:
https://spockframework.org/spock/docs/1.1/all_in_one.html
First, we need to add proper dependencies to have both Groovy and Spock supported in our Gradle project (via build.gradle file).
// Spock
implementation platform('org.apache.groovy:groovy-bom:4.0.5')
implementation 'org.apache.groovy:groovy'
testImplementation platform("org.spockframework:spock-bom:2.3-groovy-4.0")
testImplementation "org.spockframework:spock-core"
testImplementation "org.spockframework:spock-junit4"We also want to write some integration tests that we want to have in different source set. Therefore, let's declare it (also in build.gradle file):
sourceSets {
integrationTest {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
compileClasspath += sourceSets.test.output
runtimeClasspath += sourceSets.test.output
}
}
configurations {
integrationTestImplementation.extendsFrom implementation
integrationTestImplementation.extendsFrom testImplementation
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
}Next step is to register new task for running integration tests:
tasks.register('integrationTest', Test) {
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
shouldRunAfter test
useJUnitPlatform()
}
check.dependsOn integrationTestLastly, we need to provide one additional dependency that will be used only in integration tests and it is related to IT tests in Spring Boot.
integrationTestImplementation "org.spockframework:spock-spring"π₯ This part will be available after workshops π₯
π₯ This part will be available after workshops π₯