Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79c2f159e1 | ||
|
|
b99f90132a | ||
|
|
3d6b7b4d58 | ||
|
|
d1399dac02 | ||
|
|
59d8fe7a4f |
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
public class CLIReporter extends AbstractReporter {
|
public class CLIReporter extends AbstractReporter {
|
||||||
final int terminalWidth = 80;
|
final int terminalWidth = 80;
|
||||||
|
|
||||||
|
public CLIReporter(AbstractTestReportFormatter formatter) {
|
||||||
|
super(null, formatter);
|
||||||
|
}
|
||||||
|
|
||||||
public CLIReporter(ArrayList<AbstractMap.SimpleEntry<AbstractTestCommandMetaDataFactory, Boolean>> metadata, AbstractTestReportFormatter formatter) {
|
public CLIReporter(ArrayList<AbstractMap.SimpleEntry<AbstractTestCommandMetaDataFactory, Boolean>> metadata, AbstractTestReportFormatter formatter) {
|
||||||
super(metadata, formatter);
|
super(metadata, formatter);
|
||||||
}
|
}
|
||||||
@@ -20,15 +24,15 @@ public class CLIReporter extends AbstractReporter {
|
|||||||
int passed = count(testData, true);
|
int passed = count(testData, true);
|
||||||
int failed = count(testData, false);
|
int failed = count(testData, false);
|
||||||
|
|
||||||
System.out.printf("%s\n", center(" Tests "));
|
System.out.printf("%s\n\n", center(" Tests "));
|
||||||
printTests(testData);
|
printTests(testData);
|
||||||
|
|
||||||
if(failed != 0) {
|
if(failed != 0) {
|
||||||
System.out.printf("\n%s\n", center(" Errors "));
|
System.out.printf("%s\n\n", center(" Errors "));
|
||||||
printTests(failedTestData);
|
printTests(failedTestData);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.printf("\n%s\n", center(" Summary "));
|
System.out.printf("%s\n", center(" Summary "));
|
||||||
System.out.print(summary(passed, failed));
|
System.out.print(summary(passed, failed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -25,10 +25,10 @@ public class SimpleTestReportFormatter extends AbstractTestReportFormatter {
|
|||||||
|
|
||||||
for(int i=1; i<getTestMetaData().size(); ++i) {
|
for(int i=1; i<getTestMetaData().size(); ++i) {
|
||||||
AbstractMap.SimpleEntry<String, String> pair = getTestMetaData().get(i);
|
AbstractMap.SimpleEntry<String, String> pair = getTestMetaData().get(i);
|
||||||
result += String.format("\t%s %s\n", pair.getKey(), pair.getValue());
|
result += String.format("\t%s: %s\n", pair.getKey(), pair.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassedIcon() {
|
public String getPassedIcon() {
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package space.kklochko.simple_jbdd.tests.runners;
|
||||||
|
|
||||||
|
import space.kklochko.simple_jbdd.tests.Test;
|
||||||
|
import space.kklochko.simple_jbdd.tests.commands.AbstractTestCommand;
|
||||||
|
import space.kklochko.simple_jbdd.tests.factories.AbstractTestRunnerFactory;
|
||||||
|
import space.kklochko.simple_jbdd.tests.factories.TestCommandQueueFactory;
|
||||||
|
import space.kklochko.simple_jbdd.tests.factories.meta.AbstractTestCommandMetaDataFactory;
|
||||||
|
import space.kklochko.simple_jbdd.tests.factories.meta.TestCommandMetaDataFactory;
|
||||||
|
import space.kklochko.simple_jbdd.tests.loaders.AbstractNameClassLoader;
|
||||||
|
import space.kklochko.simple_jbdd.tests.loaders.SingleTestLoader;
|
||||||
|
import space.kklochko.simple_jbdd.tests.reports.AbstractReporter;
|
||||||
|
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class CLITestRunner extends AbstractTestRunner {
|
||||||
|
private ArrayList<AbstractTestCommand<Test>> commands;
|
||||||
|
private AbstractNameClassLoader classLoader;
|
||||||
|
private AbstractTestRunnerFactory runnerFactory;
|
||||||
|
private AbstractReporter reporter;
|
||||||
|
|
||||||
|
public CLITestRunner(AbstractNameClassLoader classLoader, AbstractTestRunnerFactory runnerFactory, AbstractReporter reporter) {
|
||||||
|
setClassLoader(classLoader);
|
||||||
|
setRunnerFactory(runnerFactory);
|
||||||
|
setReporter(reporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean run() {
|
||||||
|
commands = createCommands(load());
|
||||||
|
ArrayList<Boolean> testStatuses = runTests(commands);
|
||||||
|
report(createMetadata(commands, testStatuses));
|
||||||
|
|
||||||
|
return isFailed(testStatuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Test> load() {
|
||||||
|
Set<Class<?>> classes = this.classLoader.load();
|
||||||
|
ArrayList<Test> tests = new ArrayList();
|
||||||
|
|
||||||
|
for(var aClass : classes) {
|
||||||
|
tests.add((new SingleTestLoader(aClass.getName())).load());
|
||||||
|
}
|
||||||
|
|
||||||
|
return tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<AbstractTestCommand<Test>> createCommands(ArrayList<Test> tests) {
|
||||||
|
TestCommandQueueFactory factory = new TestCommandQueueFactory(tests);
|
||||||
|
return factory.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Boolean> runTests(ArrayList<AbstractTestCommand<Test>> commands) {
|
||||||
|
return commands.stream()
|
||||||
|
.map(c -> runnerFactory.create(c).run())
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<AbstractMap.SimpleEntry<AbstractTestCommandMetaDataFactory, Boolean>> createMetadata(ArrayList<AbstractTestCommand<Test>> commands, ArrayList<Boolean> testStatuses) {
|
||||||
|
return IntStream.range(0, commands.size())
|
||||||
|
.mapToObj(i -> new AbstractMap.SimpleEntry<AbstractTestCommandMetaDataFactory, Boolean>(
|
||||||
|
new TestCommandMetaDataFactory(commands.get(i)),
|
||||||
|
testStatuses.get(i)))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void report(ArrayList<AbstractMap.SimpleEntry<AbstractTestCommandMetaDataFactory, Boolean>> metadata) {
|
||||||
|
reporter.setMetadata(metadata);
|
||||||
|
reporter.report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFailed(ArrayList<Boolean> testStatuses) {
|
||||||
|
return !testStatuses.stream().anyMatch(b -> b == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractNameClassLoader getClassLoader() {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClassLoader(AbstractNameClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractTestRunnerFactory getRunnerFactory() {
|
||||||
|
return runnerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunnerFactory(AbstractTestRunnerFactory runnerFactory) {
|
||||||
|
this.runnerFactory = runnerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractReporter getReporter() {
|
||||||
|
return reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReporter(AbstractReporter reporter) {
|
||||||
|
this.reporter = reporter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+4
-4
@@ -36,8 +36,8 @@ class SimpleTestReportFormatterSpec extends Specification {
|
|||||||
|
|
||||||
where: "Possible variants of tests"
|
where: "Possible variants of tests"
|
||||||
isPassed || expectedFormat
|
isPassed || expectedFormat
|
||||||
true || "✓ A simple test\n\tThen Then block\n"
|
true || "✓ A simple test\n\tThen: Then block\n\n"
|
||||||
false || "⨯ A simple test\n\tThen Then block\n"
|
false || "⨯ A simple test\n\tThen: Then block\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
def "If the map of methods have GivenWhenThen blocks."() {
|
def "If the map of methods have GivenWhenThen blocks."() {
|
||||||
@@ -61,8 +61,8 @@ class SimpleTestReportFormatterSpec extends Specification {
|
|||||||
|
|
||||||
where: "Possible variants of tests"
|
where: "Possible variants of tests"
|
||||||
isPassed || expectedFormat
|
isPassed || expectedFormat
|
||||||
true || "✓ A simple test\n\tGiven Given block\n\tWhen When block\n\tThen Then block\n"
|
true || "✓ A simple test\n\tGiven: Given block\n\tWhen: When block\n\tThen: Then block\n\n"
|
||||||
false || "⨯ A simple test\n\tGiven Given block\n\tWhen When block\n\tThen Then block\n"
|
false || "⨯ A simple test\n\tGiven: Given block\n\tWhen: When block\n\tThen: Then block\n\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user