diff --git a/pom.xml b/pom.xml index d596e497..3eb82399 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ UTF-8 + 1.1.40 @@ -37,6 +38,21 @@ guava 19.0 + + net.serenity-bdd + serenity-core + ${serenity.version} + + + net.serenity-bdd + serenity-junit + ${serenity.version} + + + net.serenity-bdd + serenity-screenplay + ${serenity.version} + diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/APetHotel.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/APetHotel.java index 6a5c242b..d12a369d 100644 --- a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/APetHotel.java +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/APetHotel.java @@ -30,13 +30,21 @@ private Pet somePet(int petCount) { private final static Random random = new Random(); private Breed someBreed() { - return Breed.values()[ random.nextInt(Breed.values().length) ]; + return Breed.values()[random.nextInt(Breed.values().length)]; } - private final static List PET_NAMES = ImmutableList.of("Fido","Felix","Rover","Spot"); + private final static List PET_NAMES = ImmutableList.of("Fido", "Felix", "Rover", "Spot"); private String someName(int petCount) { return PET_NAMES.get(random.nextInt(PET_NAMES.size())) + " " + petCount; } + + public PetHotel checkedIn() { + PetHotel petHotel = new PetHotel(); + for (int i = 1; i <= petCount; i++) { + petHotel.checkIn(Pet.cat().named("Pet - " + i)); //adding random 20 pets as of now + } + return petHotel; + } } } diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/BookingResponse.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/BookingResponse.java new file mode 100644 index 00000000..edf0a947 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/BookingResponse.java @@ -0,0 +1,26 @@ +package serenitylabs.tutorials.vetclinic.collections.katas; + +/** + * Created by vdheer on 9/20/2016. + */ +public class BookingResponse { + private boolean petsAdded; + + public BookingResponse(boolean petsAdded) { + this.petsAdded = petsAdded; + } + + public BookingResponse() { + + } + + public boolean isConfirmed() { + return petsAdded; + } + + public boolean isOnWaitingList() { + return !petsAdded; + } + + +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/PetHotel.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/PetHotel.java new file mode 100644 index 00000000..9c42114a --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/PetHotel.java @@ -0,0 +1,39 @@ +package serenitylabs.tutorials.vetclinic.collections.katas; + +import serenitylabs.tutorials.vetclinic.Pet; + +import java.util.*; + +import static java.util.Comparator.comparing; + +/** + * Created by vdheer on 9/20/2016. + */ +public class PetHotel { + private final Collection registeredPets = new TreeSet<>(comparing(Pet::getName)); + private final Queue waitingListOfPets = new LinkedList<>(); + private static final int DEFAULT_MAXIMUM_CAPACITY = 20; + + private static String hotelName; + + public List getRegisteredPets() { + return new ArrayList<>(registeredPets); + } + + public BookingResponse checkIn(Pet pet) { + return (registeredPets.size() < DEFAULT_MAXIMUM_CAPACITY) + ? new BookingResponse(registeredPets.add(pet)) + : new BookingResponse(waitingListOfPets.add(pet)); + } + + public List getWaitingList() { + return new ArrayList<>(waitingListOfPets); + } + + public void checkOut(Pet pet) { + if (!waitingListOfPets.isEmpty()) { + registeredPets.remove(pet); + checkIn(waitingListOfPets.poll()); + } + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/abilities/ManageThehotel.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/abilities/ManageThehotel.java new file mode 100644 index 00000000..4b628da9 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/abilities/ManageThehotel.java @@ -0,0 +1,30 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.abilities; + +import net.serenitybdd.screenplay.Ability; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.PetHotel; + +import java.util.List; + +/** + * Created by vdheer on 9/20/2016. + */ +public class ManageThehotel implements Ability { + private PetHotel petHotel; + + public ManageThehotel(PetHotel petHotel) { + this.petHotel = petHotel; + } + +// public void checkIn(Pet pet) { +// petHotel.checkIn(pet); +// } + + public List getRegisteredPets() { + return petHotel.getRegisteredPets(); + } + + public List getPetsOnWaitingList() { + return petHotel.getWaitingList(); + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheBookingStatus.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheBookingStatus.java new file mode 100644 index 00000000..ab4da383 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheBookingStatus.java @@ -0,0 +1,41 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.questions; + +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Question; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.BookingResponse; + +/** + * Created by vdheer on 9/20/2016. + */ +public class TheBookingStatus implements Question { + + private BookingResponse bookingResponse = new BookingResponse(true); + + private Pet pet; + + public TheBookingStatus(Pet pet) { + this.pet = pet; + } + + public static TheStatusBuilder of(Pet pet) { + return new TheStatusBuilder(pet); + } + + @Override + public Boolean answeredBy(Actor actor) { + return bookingResponse.isConfirmed(); + } + + public static class TheStatusBuilder { + private Pet pet; + + public TheStatusBuilder(Pet pet) { + this.pet = pet; + } + + public Question isConfirmed() { + return new TheBookingStatus(pet); + } + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheRegisteredGuest.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheRegisteredGuest.java new file mode 100644 index 00000000..708ba621 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheRegisteredGuest.java @@ -0,0 +1,30 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.questions; + +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Question; +import net.serenitybdd.screenplay.annotations.Subject; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.PetHotel; + +import java.util.List; + +/** + * Created by vdheer on 9/20/2016. + */ +@Subject("the Pets in the hotel") +public class TheRegisteredGuest implements Question> { + private PetHotel petHotel; + + public TheRegisteredGuest(PetHotel petHotel) { + this.petHotel = petHotel; + } + + @Override + public List answeredBy(Actor actor) { + return petHotel.getRegisteredPets(); + } + + public static Question> registeredIn(PetHotel petHotel) { + return new TheRegisteredGuest(petHotel); + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingGuest.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingGuest.java new file mode 100644 index 00000000..0fa037e2 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingGuest.java @@ -0,0 +1,30 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.questions; + +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Question; +import net.serenitybdd.screenplay.annotations.Subject; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.PetHotel; + +import java.util.List; + +/** + * Created by vdheer on 9/20/2016. + */ +@Subject("the Waiting Pets in the hotel") +public class TheWaitingGuest implements Question> { + private PetHotel petHotel; + + public TheWaitingGuest(PetHotel petHotel) { + this.petHotel = petHotel; + } + + @Override + public List answeredBy(Actor actor) { + return petHotel.getWaitingList(); + } + + public static Question> isOnWaitingListIn(PetHotel petHotel) { + return new TheWaitingGuest(petHotel); + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingStatus.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingStatus.java new file mode 100644 index 00000000..2e4f1259 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/questions/TheWaitingStatus.java @@ -0,0 +1,40 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.questions; + +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Question; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.BookingResponse; + +/** + * Created by vdheer on 9/20/2016. + */ +public class TheWaitingStatus implements Question { + + private BookingResponse bookingResponse = new BookingResponse(); + private Pet pet; + + public TheWaitingStatus(Pet pet) { + this.pet = pet; + } + + @Override + public Boolean answeredBy(Actor actor) { + return bookingResponse.isConfirmed(); + } + + public static TheWaitingStatusBuilder of(Pet pet) { + return new TheWaitingStatusBuilder(pet); + } + + public static class TheWaitingStatusBuilder { + private Pet pet; + + public TheWaitingStatusBuilder(Pet pet) { + this.pet = pet; + } + + public Question isConfirmed() { + return new TheWaitingStatus(pet); + } + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckIn.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckIn.java new file mode 100644 index 00000000..1c3e8c51 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckIn.java @@ -0,0 +1,48 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.tasks; + + +import net.serenitybdd.core.steps.Instrumented; +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Performable; +import net.serenitybdd.screenplay.Task; +import net.thucydides.core.annotations.Step; +import org.jruby.ir.instructions.Instr; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.BookingResponse; +import serenitylabs.tutorials.vetclinic.collections.katas.PetHotel; + +/** + * Created by vdheer on 9/20/2016. + */ +public class CheckIn implements Performable { + private final Pet pet; + private final PetHotel petHotel; + + public CheckIn(Pet pet, PetHotel petHotel) { + this.pet = pet; + this.petHotel = petHotel; + } + + @Step("{0} checks-in #pet into #petHotel") + @Override + public void performAs(T actor) { + BookingResponse bookingResponse = petHotel.checkIn(pet); + } + + public static CheckInBuilder aPet(Pet pet) { + return new CheckInBuilder(pet); + } + + public static class CheckInBuilder { + private Pet pet; + + public CheckInBuilder(Pet pet) { + this.pet = pet; + } + + public Performable in(PetHotel petHotel) { + //return new CheckIn(pet, petHotel); + return Instrumented.instanceOf(CheckIn.class).withProperties(pet, petHotel); + } + } +} diff --git a/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckOut.java b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckOut.java new file mode 100644 index 00000000..8b891a05 --- /dev/null +++ b/src/main/java/serenitylabs/tutorials/vetclinic/collections/katas/tasks/CheckOut.java @@ -0,0 +1,44 @@ +package serenitylabs.tutorials.vetclinic.collections.katas.tasks; + +import net.serenitybdd.core.steps.Instrumented; +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.Performable; +import net.serenitybdd.screenplay.Task; +import net.thucydides.core.annotations.Step; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.PetHotel; + +/** + * Created by vdheer on 9/20/2016. + */ +public class CheckOut implements Performable { + private final Pet pet; + private final PetHotel petHotel; + + public CheckOut(Pet pet, PetHotel petHotel) { + this.pet = pet; + this.petHotel = petHotel; + } + + @Step("{0} checks-in #pet into #petHotel") + @Override + public void performAs(T actor) { + petHotel.checkOut(pet); + } + + public static CheckOutBuilder aPet(Pet pet) { + return new CheckOutBuilder(pet); + } + + public static class CheckOutBuilder { + private Object pet; + + public CheckOutBuilder(Object pet) { + this.pet = pet; + } + + public Performable in(PetHotel petHotel) { + return Instrumented.instanceOf(CheckOut.class).withProperties(pet, petHotel); + } + } +} diff --git a/src/test/java/serenitylabs/tutorials/vetclinic/README.md b/src/test/java/serenitylabs/tutorials/vetclinic/README.md new file mode 100644 index 00000000..8b2ec7b8 --- /dev/null +++ b/src/test/java/serenitylabs/tutorials/vetclinic/README.md @@ -0,0 +1 @@ +Your test code goes here. diff --git a/src/test/java/serenitylabs/tutorials/vetclinic/collections/katas/WhenBookingPetsIntoAPetHotel.java b/src/test/java/serenitylabs/tutorials/vetclinic/collections/katas/WhenBookingPetsIntoAPetHotel.java index 5486b552..05392e58 100644 --- a/src/test/java/serenitylabs/tutorials/vetclinic/collections/katas/WhenBookingPetsIntoAPetHotel.java +++ b/src/test/java/serenitylabs/tutorials/vetclinic/collections/katas/WhenBookingPetsIntoAPetHotel.java @@ -1,54 +1,186 @@ package serenitylabs.tutorials.vetclinic.collections.katas; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.screenplay.Actor; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import serenitylabs.tutorials.vetclinic.Pet; +import serenitylabs.tutorials.vetclinic.collections.katas.questions.TheRegisteredGuest; +import serenitylabs.tutorials.vetclinic.collections.katas.questions.TheBookingStatus; +import serenitylabs.tutorials.vetclinic.collections.katas.questions.TheWaitingGuest; +import serenitylabs.tutorials.vetclinic.collections.katas.questions.TheWaitingStatus; +import serenitylabs.tutorials.vetclinic.collections.katas.tasks.CheckIn; +import serenitylabs.tutorials.vetclinic.collections.katas.tasks.CheckOut; +import static net.serenitybdd.screenplay.GivenWhenThen.*; +import static org.hamcrest.Matchers.*; + + +@RunWith(SerenityRunner.class) public class WhenBookingPetsIntoAPetHotel { + Actor vikrant, john; + PetHotel petHotel; + + @Before + public void setUp() { + petHotel = new PetHotel(); + vikrant = Actor.named("Vikrant Dheer"); + john = Actor.named("John Smart"); + } @Test public void the_hotel_should_initially_have_no_pets_booked() { + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), hasSize(0))); } @Test public void should_be_able_to_check_a_pet_into_the_hotel() throws Exception { + //GIVEN + Pet tommy = Pet.dog().named("Tommy"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), hasItem(tommy))); } @Test public void should_be_able_to_check_in_several_pets() throws Exception { + //GIVEN + Pet tommy = Pet.dog().named("Tommy"); + Pet goldy = Pet.fish().named("Goldy"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel), CheckIn.aPet(goldy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), hasItems(goldy, tommy))); } @Test public void should_not_be_able_to_check_in_the_same_pet_twice() throws Exception { - } + //GIVEN + Pet tommy = Pet.dog().named("Tommy"); + Pet goldy = Pet.fish().named("Goldy"); - @Test - public void should_be_able_to_retrieve_checked_in_pets_in_alphabetical_order() throws Exception { + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel), + CheckIn.aPet(goldy).in(petHotel), + CheckIn.aPet(tommy).in(petHotel)); //again checkin tommy + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), containsInAnyOrder(goldy, tommy))); } @Test - public void should_be_able_to_obtain_a_booking_confirmation_when_we_check_in_a_pet() throws Exception { + public void should_be_able_to_retrieve_checked_in_pets_in_alphabetical_order() throws Exception { + //GIVEN + Pet zira = Pet.dog().named("Zira the Dog"); + Pet goldy = Pet.fish().named("Goldy the Fish"); + Pet anabelle = Pet.cat().named("Anabelle the Cat"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(zira).in(petHotel), + CheckIn.aPet(anabelle).in(petHotel), + CheckIn.aPet(goldy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), contains(anabelle, goldy, zira))); } @Test public void should_not_be_able_to_check_in_pets_beyond_hotel_capacity() throws Exception { - } + //GIVEN + PetHotel petHotel = APetHotel.with(20).checkedIn(); //adding random 20 pets as of now + Pet tommy = Pet.dog().named("Tommy"); - @Test - public void should_notify_owner_that_the_hotel_is_full() throws Exception { - } + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), not(hasItem(tommy)))); + } @Test public void should_place_pets_on_a_waiting_list_when_the_hotel_is_full() throws Exception { + //GIVEN + PetHotel petHotel = APetHotel.with(20).checkedIn(); //adding random 20 pets as of now + Pet tommy = Pet.dog().named("Tommy"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheWaitingGuest.isOnWaitingListIn(petHotel), hasItem(tommy))); } @Test public void pets_on_the_waiting_list_should_be_added_to_the_hotel_when_a_place_is_freed() throws Exception { + //GIVEN + PetHotel petHotel = APetHotel.with(19).checkedIn(); //adding random 20 pets as of now + Pet tommy = Pet.dog().named("Tommy"); + Pet goldy = Pet.fish().named("Goldy the Fish"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); //VIKRANT trying to checkin + + when(john).attemptsTo(CheckIn.aPet(goldy).in(petHotel)); //JOHN trying to checkin + + when(vikrant).attemptsTo(CheckOut.aPet(tommy).in(petHotel)); //VIKRANT trying to checkout + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), hasItem(goldy))); } @Test public void pets_on_the_waiting_list_should_be_admitted_on_a_first_come_first_served_basis() throws Exception { + //GIVEN + PetHotel petHotel = APetHotel.with(19).checkedIn(); //adding random 20 pets as of now + Pet tommy = Pet.dog().named("Tommy"); + Pet goldy = Pet.fish().named("Goldy the Fish"); + Pet anabelle = Pet.cat().named("Anabelle the Cat"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); //VIKRANT trying to checkin + + when(john).attemptsTo(CheckIn.aPet(goldy).in(petHotel)); //JOHN trying to checkin + + when(vikrant).attemptsTo(CheckIn.aPet(anabelle).in(petHotel)); //VIKRANT trying to checkin + + when(vikrant).attemptsTo(CheckOut.aPet(tommy).in(petHotel)); //VIKRANT trying to checkout + + //THEN + then(vikrant).should(seeThat(TheRegisteredGuest.registeredIn(petHotel), hasItem(goldy)), + seeThat(TheWaitingGuest.isOnWaitingListIn(petHotel), hasItem(anabelle))); + } + + @Test + public void should_be_able_to_obtain_a_booking_confirmation_when_we_check_in_a_pet() throws Exception { + //GIVEN + Pet tommy = Pet.dog().named("Tommy"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheBookingStatus.of(tommy).isConfirmed(), is(true))); } + @Test + public void should_notify_owner_that_the_hotel_is_full() throws Exception { + //GIVEN + PetHotel petHotel = APetHotel.with(19).checkedIn(); + Pet tommy = Pet.dog().named("Tommy"); + Pet goldy = Pet.fish().named("Goldy"); + + //WHEN + when(vikrant).attemptsTo(CheckIn.aPet(tommy).in(petHotel), CheckIn.aPet(goldy).in(petHotel)); + + //THEN + then(vikrant).should(seeThat(TheWaitingStatus.of(goldy).isConfirmed(), is(false))); + } } diff --git a/src/test/java/serenitylabs/tutorials/vetclinic/package-info.java b/src/test/java/serenitylabs/tutorials/vetclinic/package-info.java deleted file mode 100644 index 481a4ac9..00000000 --- a/src/test/java/serenitylabs/tutorials/vetclinic/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Unit tests for the Vet Clinic app - **/ - package serenitylabs.tutorials.vetclinic;