diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml
index 7aff0a93e0..1fd6357b87 100644
--- a/testing-modules/testing/pom.xml
+++ b/testing-modules/testing/pom.xml
@@ -94,6 +94,11 @@
1.5
test
+
+ org.javalite
+ javalite-common
+ ${javalite.version}
+
@@ -162,5 +167,6 @@
0.32
1.1.0
0.12
+ 1.4.13
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java
new file mode 100644
index 0000000000..efb4c62bde
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java
@@ -0,0 +1,41 @@
+package com.baeldung.jspec;
+
+public abstract class Animal {
+
+ protected String name;
+
+ public Animal(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Animal other = (Animal) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java
new file mode 100644
index 0000000000..73ea343600
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java
@@ -0,0 +1,48 @@
+package com.baeldung.jspec;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Cage {
+
+ private Set animals = new HashSet<>();
+
+ public void put(Animal animal) {
+ animals.add(animal);
+ }
+
+ public void put(Animal... animals) {
+ this.animals.addAll(Arrays.asList(animals));
+ }
+
+ public Animal release(Animal animal) {
+ return animals.remove(animal) ? animal : null;
+ }
+
+ public void open() {
+ animals.clear();
+ }
+
+ public boolean hasAnimals() {
+ return animals.size() > 0;
+ }
+
+ public boolean isEmpty() {
+ return animals.isEmpty();
+ }
+
+ public Set getAnimals() {
+ return this.animals;
+ }
+
+ public int size() {
+ return animals.size();
+ }
+
+ @Override
+ public String toString() {
+ return "Cage [animals=" + animals + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java
new file mode 100644
index 0000000000..5021a1481c
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java
@@ -0,0 +1,14 @@
+package com.baeldung.jspec;
+
+public class Cat extends Animal {
+
+ public Cat(String name) {
+ super(name);
+ }
+
+ @Override
+ public String toString() {
+ return "Cat [name=" + name + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java
new file mode 100644
index 0000000000..43626941e3
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java
@@ -0,0 +1,14 @@
+package com.baeldung.jspec;
+
+public class Dog extends Animal {
+
+ public Dog(String name) {
+ super(name);
+ }
+
+ @Override
+ public String toString() {
+ return "Dog [name=" + name + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java
new file mode 100644
index 0000000000..33ef986588
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java
@@ -0,0 +1,126 @@
+package com.baeldung.jspec;
+
+import static org.javalite.test.jspec.JSpec.$;
+import static org.javalite.test.jspec.JSpec.expect;
+import static org.javalite.test.jspec.JSpec.the;
+
+import java.util.Set;
+
+import org.javalite.test.jspec.DifferenceExpectation;
+import org.junit.Test;
+
+public class CageUnitTest {
+
+ Cat tomCat = new Cat("Tom");
+ Cat felixCat = new Cat("Felix");
+ Dog boltDog = new Dog("Bolt");
+ Cage cage = new Cage();
+
+
+ @Test
+ public void puttingAnimals_shouldIncreaseCageSize() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage.size()).shouldEqual(2);
+ }
+
+ @Test
+ public void releasingAnimals_shouldDecreaseCageSize() {
+ // When
+ cage.put(tomCat, boltDog);
+ cage.release(tomCat);
+
+ // Then
+ the(cage.size()).shouldEqual(1);
+ }
+
+ @Test
+ public void puttingAnimals_shouldLeaveThemInsideTheCage() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage).shouldHave("animals");
+ }
+
+ @Test
+ public void openingTheCage_shouldReleaseAllAnimals() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage).shouldNotBe("empty");
+
+ // When
+ cage.open();
+
+ // Then
+ the(cage).shouldBe("empty");
+ the(cage.isEmpty()).shouldBeTrue();
+ }
+
+ @Test
+ public void comparingTwoDogs() {
+ // When
+ Dog firstDog = new Dog("Rex");
+ Dog secondDog = new Dog("Rex");
+
+ // Then
+ $(firstDog).shouldEqual(secondDog);
+ $(firstDog).shouldNotBeTheSameAs(secondDog);
+ }
+
+ @Test
+ public void puttingCatsOnly_shouldLetCageAnimalsToContainCats() {
+ // When
+ cage.put(tomCat, felixCat);
+
+ // Then
+ Set animals = cage.getAnimals();
+ the(animals).shouldContain(tomCat);
+ the(animals).shouldContain(felixCat);
+ the(animals).shouldNotContain(boltDog);
+ }
+
+ @Test
+ public void puttingCatsOnly_shouldLetCageToContainCats() {
+ // When
+ cage.put(tomCat, felixCat);
+
+ // Then
+ // Check with toString of the tested objects
+ the(cage).shouldContain(tomCat);
+ the(cage).shouldContain(felixCat);
+ the(cage).shouldNotContain(boltDog);
+ }
+
+ @Test
+ public void puttingMoreAnimals_shouldChangeSize() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ expect( new DifferenceExpectation(cage.size()) {
+
+ @Override
+ public Integer exec() {
+ cage.release(tomCat);
+ return cage.size();
+ }
+ } );
+ }
+
+
+ @Test
+ public void releasingTheDog_shouldReleaseAnAnimalOfDogType() {
+ // When
+ cage.put(boltDog);
+ Animal releasedAnimal = cage.release(boltDog);
+
+ // Then
+ the(releasedAnimal).shouldNotBeNull();
+ the(releasedAnimal).shouldBeA(Dog.class);
+ }
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java
new file mode 100644
index 0000000000..0e35e26728
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.jspec;
+
+import static org.javalite.test.jspec.JSpec.$;
+import static org.javalite.test.jspec.JSpec.a;
+import static org.javalite.test.jspec.JSpec.expect;
+import static org.javalite.test.jspec.JSpec.it;
+import static org.javalite.test.jspec.JSpec.the;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.javalite.test.jspec.ExceptionExpectation;
+import org.junit.Test;
+
+public class JSpecUnitTest {
+
+ @Test
+ public void onePlusTwo_shouldEqualThree() {
+ $(1 + 2).shouldEqual(3);
+ a(1 + 2).shouldEqual(3);
+ the(1 + 2).shouldEqual(3);
+ it(1 + 2).shouldEqual(3);
+ }
+
+ @Test
+ public void messageShouldContainJSpec() {
+ String message = "Welcome to JSpec demo";
+ // The message should not be empty
+ the(message).shouldNotBe("empty");
+ // The message should contain JSpec
+ the(message).shouldContain("JSpec");
+ }
+
+ public void colorsListShouldContainRed() {
+ List colorsList = Arrays.asList("red", "green", "blue");
+ $(colorsList).shouldContain("red");
+ }
+
+ public void guessedNumberShouldEqualHiddenNumber() {
+ Integer guessedNumber = 11;
+ Integer hiddenNumber = 11;
+
+ $(guessedNumber).shouldEqual(hiddenNumber);
+ $(guessedNumber).shouldNotBeTheSameAs(hiddenNumber);
+ }
+
+ @Test
+ public void dividingByThero_shouldThrowArithmeticException() {
+ expect(new ExceptionExpectation(ArithmeticException.class) {
+ @Override
+ public void exec() throws ArithmeticException {
+ System.out.println(1 / 0);
+ }
+ } );
+ }
+
+}