class ScheduleTest {
@Test
@DisplayName("should throw when scheduling for the taken date")
void scheduleOnCall_throwsWhenDateAlreadyTaken() {
}
@Test
@DisplayName("should throw when scheduling with the taken room")
void scheduleOnCall_throwsWhenRoomAlreadyTaken() {
}
@Test
@DisplayName("should schedule a new on call date")
void scheduleOnCall_worksAsExpected() {
}
@Test
@DisplayName("should throw when scheduling a visit to an absent doctor")
void scheduleNewVisit_throwsWhenDoctorUnavailable() {
}
@Test
@DisplayName("should throw when scheduling a visit for the taken date")
void scheduleNewVisit_throwsWhenDateAlreadyTaken() {
}
@Test
@DisplayName("should schedule a new visit")
void scheduleNewVisit_worksAsExpected() {
}
@Test
@DisplayName("should throw when overriding on call with a doctor with a different specialization")
void overrideOnCall_throwsWhenDifferentSpecialization() {
}
@Test
@DisplayName("should override on call")
void overrideOnCall_worksAsExpected() {
}
}
plugins {
id 'org.springframework.boot' version '2.2.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
id 'groovy'
}
ext['groovy.version'] = '3.0.1'
/* ... */
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.codehaus.groovy:groovy-all:3.0.1'
testImplementation 'org.spockframework:spock-core:2.0-M2-groovy-3.0'
}
test {
useJUnitPlatform()
}
import spock.lang.Specification
class ScheduleSpec extends Specification {
def 'should throw when scheduling for the taken date'() {
}
def 'should throw when scheduling with the taken room'() {
}
def 'should schedule a new on call date'() {
}
def 'should throw when scheduling a visit to an absent doctor'() {
}
def 'should throw when scheduling a visit for the taken date'() {
}
def 'should schedule a new visit'() {
}
def 'should throw when overriding on call with a doctor with a different specialization'() {
}
def 'should override on call'() {
}
}
class ScheduleSpec extends Specification {
def 'should throw when scheduling for the taken date'() {
expect:
true
}
def 'should throw when scheduling with the taken room'() {
expect:
true
}
def 'should schedule a new on call date'() {
expect:
true
}
def 'should throw when scheduling a visit to an absent doctor'() {
expect:
true
}
def 'should throw when scheduling a visit for the taken date'() {
expect:
true
}
def 'should schedule a new visit'() {
expect:
true
}
def 'should throw when overriding on call with a doctor with a different specialization'() {
expect:
true
}
def 'should override on call'() {
expect:
true
}
}
Groovy - idealny do DSL
def end = start + Duration.of(2, HOURS) // method "plus"
toTest.getPatient() == null // equals
entry.doctor // getDoctor()
[roomFoo, new Room('bar')] // new ArrayList()
factory() // lambda execution
toTest.snapshot.entries.sort { it.from } // collection processing
result[0] // result.get(0)
private static ScheduleEntry exampleVisit( // default params
ZonedDateTime from = start,
ZonedDateTime to = end
) { /* ... */ }
private static Doctor exampleSurgeon() {
new Doctor(Specialization.SURGEON) // look ma, no return
}thrown DateAlreadyTakenException
def 'should not execute getter'() {
given:
def room = GroovyMock(Room)
when:
new Schedule([room])
then:
0 * room.name
}
private Schedule toTest;
@BeforeEach
void init() {
toTest = new Schedule();
}
@Test
@DisplayName("should throw when scheduling for the taken date")
void scheduleOnCall_throwsWhenDateAlreadyTaken() {
// given
Doctor first = exampleSurgeon();
var start = ZonedDateTime.now();
var end = start.plusHours(2);
// and
toTest.scheduleOnCall(first, start, end);
// when
Doctor second = exampleSurgeon();
var start2 = start.plusHours(1);
// then
assertThrows(
DateAlreadyTakenException.class,
() -> toTest.scheduleOnCall(second, start2, end)
);
}
private static Doctor exampleSurgeon() {
return new Doctor(Specialization.SURGEON);
}
@Subject
private Schedule toTest
def setup() {
toTest = new Schedule()
}
def 'should throw when scheduling for the taken date'() {
given:
Doctor first = exampleSurgeon()
def start = ZonedDateTime.now()
def end = start.plusHours(2)
and:
toTest.scheduleOnCall(first, start, end)
when:
Doctor second = exampleSurgeon()
def start2 = start.plusHours(1)
and:
toTest.scheduleOnCall(second, start2, end)
then:
thrown DateAlreadyTakenException
}
private static Doctor exampleSurgeon() {
new Doctor(Specialization.SURGEON)
}
@TestFactory
@DisplayName("is identified by its values")
Stream<DynamicNode> generateEqualityTests() {
return Stream.<Supplier<ScheduleEntry>>of(
() -> new ScheduleEntry(
new Doctor(Specialization.SURGEON),
start,
end,
new Room("example"),
new Patient("Frank")
), () -> new ScheduleEntry(
new Doctor(Specialization.SURGEON),
start,
end,
new Room("example")
)
).map(factory ->
dynamicTest(
factory.get().getPatient() != null ? "with patient" : "without patient",
() -> assertEquals(factory.get(), factory.get())
)
);
}
Test DSL
@TestFactory
@DisplayName("calculateSquare")
Stream<DynamicNode> dynamicTestsWithContainers() {
Function<Integer, Long> testExecution = (input) -> toTest.calculateSquare(input);
return Stream.of(
new TestSuite("positive numbers", new TestCase[]{
new TestCase(3, 9L),
new TestCase(100, 10_000L)
}),
new TestSuite("negative numbers", new TestCase[]{
new TestCase(-3, 9L)
}),
new TestSuite("specific numbers", new TestCase[]{
new TestCase(1, 1L),
new TestCase(0, 0L)
}),
new TestSuite("big numbers", new TestCase[]{
new TestCase(Integer.MAX_VALUE, 4_611_686_014_132_420_609L),
new TestCase(Integer.MIN_VALUE, 4_611_686_018_427_387_904L)
})
).map(testSuite -> testSuite.toDynamicContainer(testExecution));
}
Spock? where!
@Unroll
def 'is identified by its values (#description)'() {
expect:
factory() == factory()
where:
factory << [
() -> new ScheduleEntry(
new Doctor(Specialization.SURGEON),
start,
end,
new Room('example'),
new Patient('Frank')
),
() -> new ScheduleEntry(
new Doctor(Specialization.SURGEON),
start,
end,
new Room('example')
)
]
description << ['with patient', 'without patient']
}
var e = assertThrows(
RoomAlreadyTakenException.class,
() -> toTest.scheduleOnCall(new ScheduleEntry(
exampleSurgeon(),
start.plusHours(1),
start.plusHours(3),
roomFoo
))
);assertEquals("Cannot schedule for a room \"foo\"", e.getMessage());
assertEquals(actual, expected)
czy
assertEquals(expected, actual)
?
then:
def e = thrown RoomAlreadyTakenException
e.message.contains(roomFoo.name)
Agregowanie
@Test
@DisplayName("should schedule a new on call date")
void scheduleOnCall_worksAsExpected() {
assertAll(
// first schedule = works as a charm!
() -> assertDoesNotThrow(() -> toTest.scheduleOnCall(exampleEntry(start, end))),
// second time? NO WAY, already scheduled
() -> assertThrows(
BusinessScheduleException.class,
() -> toTest.scheduleOnCall(exampleEntry(start, end))
)
);
}