Compare commits

..
4 Commits
Author SHA1 Message Date
KKlochko 95a29a14fe Update the tests to test the multi-block test.
continuous-integration/drone/tag Build is passing
2023-10-15 12:10:33 +03:00
KKlochko d69cf31964 Add a multi-block test. 2023-10-15 12:02:24 +03:00
KKlochko 79c2f159e1 Add the multi-block tests support.
continuous-integration/drone/tag Build is passing
2023-10-15 12:02:02 +03:00
KKlochko b99f90132a Add the main entry point.
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-10-10 21:43:19 +03:00
7 changed files with 142 additions and 51 deletions
@@ -0,0 +1,24 @@
package space.kklochko.simple_jbdd;
import space.kklochko.simple_jbdd.tests.factories.AbstractTestRunnerFactory;
import space.kklochko.simple_jbdd.tests.factories.SimpleTestRunnerFactory;
import space.kklochko.simple_jbdd.tests.loaders.NameClassLoader;
import space.kklochko.simple_jbdd.tests.reports.AbstractReporter;
import space.kklochko.simple_jbdd.tests.reports.CLIReporter;
import space.kklochko.simple_jbdd.tests.reports.fmt.SimpleTestReportFormatter;
import space.kklochko.simple_jbdd.tests.runners.CLITestRunner;
public class Main {
public static void main(String[] args) {
NameClassLoader loader = new NameClassLoader();
AbstractTestRunnerFactory testRunnerFactory = new SimpleTestRunnerFactory();
AbstractReporter reporter = new CLIReporter(new SimpleTestReportFormatter());
CLITestRunner runner = new CLITestRunner(loader, testRunnerFactory, reporter);
boolean status = runner.run();
System.exit(status ? 0 : 1);
}
}
@@ -0,0 +1,51 @@
package space.kklochko.simple_jbdd.test_examples.tests;
import space.kklochko.simple_jbdd.annotations.Given;
import space.kklochko.simple_jbdd.annotations.Then;
import space.kklochko.simple_jbdd.annotations.Title;
import space.kklochko.simple_jbdd.annotations.When;
import space.kklochko.simple_jbdd.test_examples.samples.Sum;
import space.kklochko.simple_jbdd.tests.Test;
@Title("A Simple GivenGivenWhenWhenThenThen Test for Sum")
public class SimpleGivenGivenWhenWhenThenThenTest extends Test {
private Sum sum;
private int a;
private int b;
private int c;
private int resultAB;
private int resultCB;
@Given("Create the Sum object")
void setup() {
sum = new Sum();
}
@Given("Setup the arguments")
void setupArgs() {
a = 10;
b = 20;
c = 30;
}
@When("Call the .sum(10, 20)")
void triggerAB() {
resultAB = sum.sum(a, b);
}
@When("Call the .sum(30, 20)")
void triggerCB() {
resultCB = sum.sum(c, b);
}
@Then("10 + 20 is 30")
void checkAB() {
assert 30 == resultAB;
}
@Then("30 + 20 is 50")
void checkCB() {
assert 50 == resultCB;
}
}
@@ -11,37 +11,48 @@ import space.kklochko.simple_jbdd.tests.commands.decorators.BlockDecorator;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.*;
import java.util.TreeMap;
public class TestCommandFactory { public class TestCommandFactory {
public AbstractTestCommand create(Test input) { public AbstractTestCommand create(Test input) {
Class<?> aClass = input.getClass(); Class<?> aClass = input.getClass();
Map<String, Method> test_methods = this.getTestMethods(aClass); Map<String, ArrayList<Method>> test_methods = this.getTestMethods(aClass);
AbstractTestCommand<Test> aTestCommand = createTest(aClass, input); AbstractTestCommand<Test> aTestCommand = createTest(aClass, input);
if(test_methods.containsKey("Then")) { if(test_methods.containsKey("Then")) {
Method then = test_methods.get("Then"); ArrayList<Method> thens = getMethodsInReverseOrder(test_methods, "Then");
for(Method then : thens) {
String label = then.getAnnotation(Then.class).value(); String label = then.getAnnotation(Then.class).value();
aTestCommand = new BlockDecorator<Test>(label, aTestCommand, then, "Then"); aTestCommand = new BlockDecorator<Test>(label, aTestCommand, then, "Then");
} }
}
if(test_methods.containsKey("When")) { if(test_methods.containsKey("When")) {
Method when = test_methods.get("When"); ArrayList<Method> whens = getMethodsInReverseOrder(test_methods, "When");
for(Method when : whens) {
String label = when.getAnnotation(When.class).value(); String label = when.getAnnotation(When.class).value();
aTestCommand = new BlockDecorator<Test>(label, aTestCommand, when, "When"); aTestCommand = new BlockDecorator<Test>(label, aTestCommand, when, "When");
} }
}
if(test_methods.containsKey("Given")) { if(test_methods.containsKey("Given")) {
Method when = test_methods.get("Given"); ArrayList<Method> givens = getMethodsInReverseOrder(test_methods, "Given");
String label = when.getAnnotation(Given.class).value(); for(Method given : givens) {
aTestCommand = new BlockDecorator<Test>(label, aTestCommand, when, "Given"); String label = given.getAnnotation(Given.class).value();
aTestCommand = new BlockDecorator<Test>(label, aTestCommand, given, "Given");
}
} }
return aTestCommand; return aTestCommand;
} }
private ArrayList<Method> getMethodsInReverseOrder(Map<String, ArrayList<Method>> test_methods, String key) {
ArrayList<Method> methods = test_methods.get(key);
Collections.reverse(methods);
return methods;
}
protected AbstractTestCommand<Test> createTest(Class<?> aClass, Test input) { protected AbstractTestCommand<Test> createTest(Class<?> aClass, Test input) {
Title aTitle = aClass.getAnnotation(Title.class); Title aTitle = aClass.getAnnotation(Title.class);
String title = aClass.getName(); String title = aClass.getName();
@@ -52,8 +63,8 @@ public class TestCommandFactory {
return new SimpleTestCommand<Test>(title, input); return new SimpleTestCommand<Test>(title, input);
} }
protected <T extends Test> Map<String, Method> getTestMethods(Class<?> aClass) { protected <T extends Test> Map<String, ArrayList<Method>> getTestMethods(Class<?> aClass) {
Map<String, Method> test_methods = new TreeMap<String, Method>(); Map<String, ArrayList<Method>> test_methods = new TreeMap<>();
for(Method method : aClass.getDeclaredMethods()) { for(Method method : aClass.getDeclaredMethods()) {
Annotation[] annotations = method.getAnnotations(); Annotation[] annotations = method.getAnnotations();
@@ -62,15 +73,21 @@ public class TestCommandFactory {
continue; continue;
if(method.isAnnotationPresent(Given.class)) if(method.isAnnotationPresent(Given.class))
test_methods.put("Given", method); addMethodTo(test_methods, "Given", method);
if(method.isAnnotationPresent(When.class)) if(method.isAnnotationPresent(When.class))
test_methods.put("When", method); addMethodTo(test_methods, "When", method);
if(method.isAnnotationPresent(Then.class)) if(method.isAnnotationPresent(Then.class))
test_methods.put("Then", method); addMethodTo(test_methods, "Then", method);
} }
return test_methods; return test_methods;
} }
private void addMethodTo(Map<String, ArrayList<Method>> test_methods, String key, Method method) {
ArrayList<Method> methods = test_methods.getOrDefault(key, new ArrayList<>());
methods.add(method);
test_methods.put(key, methods);
}
} }
@@ -1,5 +1,6 @@
package space.kklochko.simple_jbdd.tests.factories package space.kklochko.simple_jbdd.tests.factories
import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenGivenWhenWhenThenThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenWhenThenTest import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenWhenThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTest import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTestWithoutTitle import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTestWithoutTitle
@@ -14,19 +15,27 @@ those tests check if factory generate them right.
""") """)
@Title("Unit tests for TestCommandFactory") @Title("Unit tests for TestCommandFactory")
class TestCommandFactorySpec extends Specification { class TestCommandFactorySpec extends Specification {
def "If the map of methods have one test block."() { def "The command have the same block count."() {
given: "I have a TestCommandFactory object" given: "I have a TestCommandFactory object"
@Subject @Subject
def factory = new TestCommandFactory(); def factory = new TestCommandFactory();
and: "I also have a SimpleThenTest object" when: "If a test command have blocks"
def simpleThenTest = new SimpleThenTest() def map = factory.getTestMethods(testClass.getClass())
when: "If a test have only one block" def count = map.values()
def map = factory.getTestMethods(simpleThenTest.getClass()) .stream()
.map {it.size()}
.reduce(0) { acc, num -> acc + num }
then: "the map size is 1 method" then: "the command have the expected block count"
1 == map.size() expectedBlockCount == count
where:
testClass || expectedBlockCount
new SimpleThenTest() || 1
new SimpleGivenWhenThenTest() || 3
new SimpleGivenGivenWhenWhenThenThenTest() || 6
} }
def "createTest() sets the title to a class name if no Title annotation."() { def "createTest() sets the title to a class name if no Title annotation."() {
@@ -63,34 +72,22 @@ class TestCommandFactorySpec extends Specification {
title == test.getLabels()['Title'] title == test.getLabels()['Title']
} }
def "createTest() build a Test with only Then."() { def "createTest() build a TestCommand that contains the expected blocks."() {
given: "I have a test factory" given: "I have a test factory"
@Subject @Subject
def factory = new TestCommandFactory() def factory = new TestCommandFactory()
and: "I have a test class with Title"
def testClass = new SimpleThenTest()
when: "I build a test" when: "I build a test"
def test = factory.create(testClass) def test = factory.create(testClass)
then: "The test have title and then method" then: "The test have the expected blocks"
['Title', 'Then'].toSet() == test.getLabels().keySet() expectedBlocks.toSet() == test.getLabels().keySet()
}
def "createTest() build a Test with Given-When-Then."() { where:
given: "I have a test factory" testClass || expectedBlocks
@Subject new SimpleThenTest() || ['Title', 'Then']
def factory = new TestCommandFactory() new SimpleGivenWhenThenTest() || ['Title', 'Given', 'When', 'Then']
new SimpleGivenGivenWhenWhenThenThenTest() || ['Title', 'Given', 'When', 'Then']
and: "I have a test class with Title and Given-When-Then"
def testClass = new SimpleGivenWhenThenTest()
when: "I build a test"
def test = factory.create(testClass)
then: "The test have title and then method"
['Title', 'Given', 'When', 'Then'].toSet() == test.getLabels().keySet()
} }
} }
@@ -22,7 +22,7 @@ class IntegratedClassLoader extends Specification {
def classes = loader.load() def classes = loader.load()
then: "Checking that the test result is expected" then: "Checking that the test result is expected"
3 == classes.size() 4 == classes.size()
} }
def "The classes must be represent the Test interface."() { def "The classes must be represent the Test interface."() {
@@ -19,7 +19,7 @@ class IntegratedNameClassLoader extends Specification {
def classNames = loader.load() def classNames = loader.load()
then: "Checking that the test result is expected" then: "Checking that the test result is expected"
3 == classNames.size() 4 == classNames.size()
} }
} }
@@ -1,6 +1,7 @@
package space.kklochko.simple_jbdd.tests.runners package space.kklochko.simple_jbdd.tests.runners
import space.kklochko.simple_jbdd.test_examples.tests.SimpleFailedThenTest import space.kklochko.simple_jbdd.test_examples.tests.SimpleFailedThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenGivenWhenWhenThenThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenWhenThenTest import space.kklochko.simple_jbdd.test_examples.tests.SimpleGivenWhenThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTest import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTest
import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTestWithoutTitle import space.kklochko.simple_jbdd.test_examples.tests.SimpleThenTestWithoutTitle
@@ -38,5 +39,6 @@ class IntegratedSimpleTestRunnerSpec extends Specification {
new SimpleGivenWhenThenTest() || true new SimpleGivenWhenThenTest() || true
new SimpleThenTestWithoutTitle() || true new SimpleThenTestWithoutTitle() || true
new SimpleFailedThenTest() || false new SimpleFailedThenTest() || false
new SimpleGivenGivenWhenWhenThenThenTest() || true
} }
} }