2024-08-06
One-liner
雁子南飞时,故人忆往事。 --- 《醉柳引·故人安在兮》 · 月雩
Spring Boot Mock Database
Here's an example of a Spring Boot test with a mock database:
@SpringBootTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.NONE)
@AutoConfigureMockMvc
public class ReaderControllerTest {
@MockBean
private ReaderRepository readerRepository;
@Autowired
private MockMvc mockMvc;
@Test
void createReaderTest() throws Exception {
var reader = ReaderData.getReader();
when(readerRepository.findByEmail(anyString())).thenReturn(Optional.empty());
when(readerRepository.save(null)).thenReturn(reader);
var json = """
{ "name": "%s", "email": "%s" }
""".formatted(reader.getName(), reader.getEmail());
mockMvc
.perform(
post("/user").contentType("application/json").content(json))
.andExpect(status().isOk());
}
}
Spock vs JUnit
Spock and JUnit are both Java testing frameworks, but they have some significant differences in design, features, and usage.
Commonalities
- Testing Frameworks: Both are used for writing and running automated tests.
- Integration Tools: Both can be integrated with common build tools like Maven and Gradle.
- Unit Test Support: Both support writing unit tests.
Differences
1. Syntax and Language Features
- Spock: Uses Groovy, making test code more concise and readable. Spock specs (
Specification
) are based on Groovy DSL.class MySpec extends Specification {
def "feature method"() {
expect:
1 + 1 == 2
}
} - JUnit: Uses Java. Test classes and methods are annotated.
public class MyTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}
2. Test Lifecycle
- Spock: Uses
setup
,setupSpec
,cleanup
,cleanupSpec
for defining lifecycle methods.class MySpec extends Specification {
def setup() { /* runs before every test method */ }
def cleanup() { /* runs after every test method */ }
def setupSpec() { /* runs once before the first test method */ }
def cleanupSpec() { /* runs once after the last test method */ }
} - JUnit: Uses
@Before
,@After
,@BeforeClass
,@AfterClass
annotations.public class MyTest {
@Before
public void setUp() { /* runs before every test method */ }
@After
public void tearDown() { /* runs after every test method */ }
@BeforeClass
public static void beforeAll() { /* runs once before the first test method */ }
@AfterClass
public static void afterAll() { /* runs once after the last test method */ }
}
3. Behavior Driven Development (BDD) Support
- Spock: Built-in BDD support with
given-when-then
structure, making tests more readable and expressive.class MySpec extends Specification {
def "addition should work correctly"() {
given: "two numbers"
int a = 1
int b = 1
when: "they are added"
int result = a + b
then: "the result is correct"
result == 2
}
} - JUnit: BDD is supported via third-party libraries like Cucumber, not directly with
given-when-then
.public class MyTest {
@Test
public void testAddition() {
// given
int a = 1;
int b = 1;
// when
int result = a + b;
// then
assertEquals(2, result);
}
}
4. Parameterized Tests
- Spock: Built-in support for parameterized tests using the
where
block.class MySpec extends Specification {
def "addition should work correctly"() {
expect:
a + b == result
where:
a | b || result
1 | 1 || 2
2 | 3 || 5
}
} - JUnit: Uses
@ParameterizedTest
annotation with other annotations like@ValueSource
and@CsvSource
.@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5"
})
public void testAddition(int a, int b, int result) {
assertEquals(result, a + b);
}
5. Mocking
- Spock: Powerful built-in mocking support with
Mock
,Stub
,Spy
.class MySpec extends Specification {
def "should use mock"() {
given:
def mock = Mock(MyService)
when:
mock.doSomething()
then:
1 * mock.doSomething()
}
} - JUnit: Requires third-party mocking frameworks like Mockito.
@ExtendWith(MockitoExtension.class)
public class MyTest {
@Mock
MyService myService;
@Test
public void testMock() {
myService.doSomething();
verify(myService, times(1)).doSomething();
}
}
Summary
- Spock: Known for its concise, readable syntax and built-in BDD support. Great for complex testing logic and expressive test code.
- JUnit: Traditional and widely used Java testing framework. Good for maintaining Java syntax consistency and minimal dependencies.
Both have their strengths and weaknesses. The choice between them depends on your project needs and team preferences.