diff --git a/spring-boot-cli/samples/failures.groovy b/spring-boot-cli/samples/failures.groovy new file mode 100644 index 00000000000..8f9f60909e0 --- /dev/null +++ b/spring-boot-cli/samples/failures.groovy @@ -0,0 +1,37 @@ +class FailingJUnitTests { + @Test + void passingTest() { + assertTrue(true) + } + + @Test + void failureByAssertion() { + assertTrue(false) + } + + @Test + void failureByException() { + throw new RuntimeException("This should also be handled") + } +} + +class FailingSpockTest extends Specification { + def "this should pass"() { + expect: + name.size() == length + + where: + name | length + "Spock" | 5 + } + + def "this should fail on purpose as well"() { + when: + String text = "Greetings" + + then: + //throw new RuntimeException("This should fail!") + true == false + } + +} \ No newline at end of file diff --git a/spring-boot-cli/src/main/groovy/testers/junit.groovy b/spring-boot-cli/src/main/groovy/testers/junit.groovy index 4f86f6ba681..6523cb2c85e 100644 --- a/spring-boot-cli/src/main/groovy/testers/junit.groovy +++ b/spring-boot-cli/src/main/groovy/testers/junit.groovy @@ -31,39 +31,41 @@ import java.lang.reflect.Method */ class JUnitTester extends AbstractTester { - @Override - protected Set> findTestableClasses(List> compiled) { - // Look for @Test methods - Set> testable = new LinkedHashSet>() - for (Class clazz : compiled) { - for (Method method : clazz.getMethods()) { - for (Annotation annotation : method.getAnnotations()) { - if (annotation.toString().contains("Test")) { - testable.add(clazz) - } - } - } - } - return testable - } + @Override + protected Set> findTestableClasses(List> compiled) { + // Look for @Test methods + Set> testable = new LinkedHashSet>() + for (Class clazz : compiled) { + for (Method method : clazz.getMethods()) { + for (Annotation annotation : method.getAnnotations()) { + if (annotation.toString().contains("Test")) { + testable.add(clazz) + } + } + } + } + return testable + } - @Override - protected TestResults test(Class[] testable) { - Result results = JUnitCore.runClasses(testable) + @Override + protected TestResults test(List> testable) { + return JUnitTester.runEmbeddedTests(testable) + } - TestResults testResults = new TestResults() - testResults.setFailureCount(results.getFailureCount()) - testResults.setRunCount(results.getRunCount()) + static TestResults runEmbeddedTests(List> testable) { + Result results = JUnitCore.runClasses(testable.toArray(new Class[0])) - List failures = - new ArrayList() - for (org.junit.runner.notification.Failure failure : results.getFailures()) { - failures.add(new Failure(failure.getDescription().toString(), failure.getTrace())) - } + TestResults testResults = new TestResults() + testResults.setRunCount(results.getRunCount()) - testResults.setFailures(failures.toArray(new Failure[0])) + List failures = new ArrayList() + for (org.junit.runner.notification.Failure failure : results.getFailures()) { + failures.add(new Failure(failure.exception.toString(), failure.trace)) + } - return testResults - } + testResults.setFailures(failures) + + return testResults + } } diff --git a/spring-boot-cli/src/main/groovy/testers/spock.groovy b/spring-boot-cli/src/main/groovy/testers/spock.groovy index 5176021212a..afd34b10425 100644 --- a/spring-boot-cli/src/main/groovy/testers/spock.groovy +++ b/spring-boot-cli/src/main/groovy/testers/spock.groovy @@ -14,49 +14,34 @@ * limitations under the License. */ -import org.junit.runner.Result -import org.springframework.boot.cli.command.tester.Failure import org.springframework.boot.cli.command.tester.TestResults import spock.lang.Specification -import spock.util.EmbeddedSpecRunner /** * Groovy script to run Spock tests inside the {@link TestCommand}. * Needs to be compiled along with the actual code to work properly. * + * NOTE: SpockTester depends on JUnitTester to actually run the tests + * * @author Greg Turnquist */ class SpockTester extends AbstractTester { - @Override - protected Set> findTestableClasses(List> compiled) { - // Look for classes that implement spock.lang.Specification - Set> testable = new LinkedHashSet>() - for (Class clazz : compiled) { - if (Specification.class.isAssignableFrom(clazz)) { - testable.add(clazz) - } - } - return testable - } + @Override + protected Set> findTestableClasses(List> compiled) { + // Look for classes that implement spock.lang.Specification + Set> testable = new LinkedHashSet>() + for (Class clazz : compiled) { + if (Specification.class.isAssignableFrom(clazz)) { + testable.add(clazz) + } + } + return testable + } - @Override - protected TestResults test(Class[] testable) { - Result results = new EmbeddedSpecRunner().runClasses(Arrays.asList(testable)) - - TestResults testResults = new TestResults() - testResults.setFailureCount(results.getFailureCount()) - testResults.setRunCount(results.getRunCount()) - - List failures = - new ArrayList() - for (org.junit.runner.notification.Failure failure : results.getFailures()) { - failures.add(new Failure(failure.getDescription().toString(), failure.getTrace())) - } - - testResults.setFailures(failures.toArray(new Failure[0])) - - return testResults - } + @Override + protected TestResults test(List> testable) { + return JUnitTester.runEmbeddedTests(testable) + } } diff --git a/spring-boot-cli/src/main/groovy/testers/tester.groovy b/spring-boot-cli/src/main/groovy/testers/tester.groovy index ce286fe90ad..40dcb257a8e 100644 --- a/spring-boot-cli/src/main/groovy/testers/tester.groovy +++ b/spring-boot-cli/src/main/groovy/testers/tester.groovy @@ -25,18 +25,18 @@ import org.springframework.boot.cli.command.tester.TestResults */ public abstract class AbstractTester { - public TestResults findAndTest(List> compiled) throws FileNotFoundException { - Set> testable = findTestableClasses(compiled) + public TestResults findAndTest(List> compiled) throws FileNotFoundException { + Set> testable = findTestableClasses(compiled) - if (testable.size() == 0) { - return TestResults.NONE - } + if (testable.size() == 0) { + return TestResults.NONE + } - return test(testable.toArray(new Class[0])) - } + return test(new ArrayList>(testable)) + } - protected abstract Set> findTestableClasses(List> compiled) + protected abstract Set> findTestableClasses(List> compiled) - protected abstract TestResults test(Class[] testable) + protected abstract TestResults test(List> testable) } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java index b4e50d9e094..49fa75cef19 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java @@ -88,7 +88,6 @@ public class TestCommand extends OptionParsingCommand { private static class TestOptionHandler extends OptionHandler { private final GroovyCompiler compiler; - private TestResults results; public TestOptionHandler() { @@ -113,11 +112,12 @@ public class TestCommand extends OptionParsingCommand { * against the composite AST. */ - // Compile - Pass 1 - collect testers + // Compile - Pass 1 - compile source code to see what test libraries were + // pulled in Object[] sources = this.compiler.sources(fileOptions.getFilesArray()); - Set testerFiles = compileAndCollectTesterFiles(sources); + List testerFiles = compileAndCollectTesterFiles(sources); - // Compile - Pass 2 - with appropriate testers added in + // Compile - Pass 2 - add appropriate testers List files = new ArrayList(fileOptions.getFiles()); files.addAll(testerFiles); sources = this.compiler.sources(files.toArray(new File[files.size()])); @@ -145,14 +145,17 @@ public class TestCommand extends OptionParsingCommand { GroovyObject obj = (GroovyObject) tester.newInstance(); this.results.add((TestResults) obj.invokeMethod("findAndTest", compiled)); } + printReport(this.results); } - private Set compileAndCollectTesterFiles(Object[] sources) + private List compileAndCollectTesterFiles(Object[] sources) throws CompilationFailedException, IOException { - Set testerFiles = new LinkedHashSet(); - addTesterOnClass(sources, "org.junit.Test", "junit", testerFiles); - addTesterOnClass(sources, "spock.lang.Specification", "spock", testerFiles); + Set testerUnits = new LinkedHashSet(); + List testerFiles = new ArrayList(); + addTesterOnClass(sources, "org.junit.Test", testerFiles, testerUnits, "junit"); + addTesterOnClass(sources, "spock.lang.Specification", testerFiles, + testerUnits, "junit", "spock"); if (!testerFiles.isEmpty()) { testerFiles.add(createTempTesterFile("tester")); } @@ -161,12 +164,16 @@ public class TestCommand extends OptionParsingCommand { } private void addTesterOnClass(Object[] sources, String className, - String testerName, Set testerFiles) { + List testerFiles, Set testerUnits, String... testerNames) { for (Object source : sources) { if (source instanceof Class) { try { ((Class) source).getClassLoader().loadClass(className); - testerFiles.add(createTempTesterFile(testerName)); + for (String testerName : testerNames) { + if (testerUnits.add(testerName)) { + testerFiles.add(createTempTesterFile(testerName)); + } + } return; } catch (ClassNotFoundException ex) { @@ -201,7 +208,7 @@ public class TestCommand extends OptionParsingCommand { String trailer = ""; String trace = ""; for (Failure failure : results.getFailures()) { - trailer += failure.getDescription().toString(); + trailer += "Failed: " + failure.getDescription().toString() + "\n"; trace += failure.getTrace() + "\n"; } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/tester/TestResults.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/tester/TestResults.java index 360f8c21c21..53835427497 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/tester/TestResults.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/tester/TestResults.java @@ -16,7 +16,7 @@ package org.springframework.boot.cli.command.tester; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; /** @@ -42,8 +42,8 @@ public class TestResults { } @Override - public Failure[] getFailures() { - return new Failure[0]; + public List getFailures() { + return new ArrayList(); } @Override @@ -52,23 +52,16 @@ public class TestResults { } }; - - private int runCount; - - private int failureCount; - - private Failure[] failures = new Failure[0]; + private int runCount = 0; + private List failures = new ArrayList(); public void add(TestResults results) { this.runCount += results.getRunCount(); - this.failureCount += results.getFailureCount(); - List failures = Arrays.asList(this.failures); - failures.addAll(Arrays.asList(results.getFailures())); - this.failures = failures.toArray(new Failure[] {}); + this.failures.addAll(results.getFailures()); } public boolean wasSuccessful() { - return this.failureCount == 0; + return this.failures.size() == 0; } public int getRunCount() { @@ -80,18 +73,14 @@ public class TestResults { } public int getFailureCount() { - return this.failureCount; + return this.failures.size(); } - public void setFailureCount(int failureCount) { - this.failureCount = failureCount; - } - - public Failure[] getFailures() { + public List getFailures() { return this.failures; } - public void setFailures(Failure[] failures) { + public void setFailures(List failures) { this.failures = failures; } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpockCompilerAutoConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpockCompilerAutoConfiguration.java index 3c626857b01..cbd707558f5 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpockCompilerAutoConfiguration.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpockCompilerAutoConfiguration.java @@ -38,12 +38,16 @@ public class SpockCompilerAutoConfiguration extends CompilerAutoConfiguration { @Override public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException { - dependencies.add("spock-core"); + dependencies.add("spock-core").add("junit").add("spring-test") + .add("hamcrest-library"); } @Override public void applyImports(ImportCustomizer imports) throws CompilationFailedException { - imports.addStarImports("spock.lang"); + imports.addStarImports("spock.lang").addStarImports("org.junit") + .addStaticStars("org.junit.Assert") + .addStaticStars("org.hamcrest.MatcherAssert") + .addStaticStars("org.hamcrest.Matchers"); } } diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/TestCommandIntegrationTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/TestCommandIntegrationTests.java index f3c446703de..8b14af35041 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/TestCommandIntegrationTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/TestCommandIntegrationTests.java @@ -25,6 +25,7 @@ import org.springframework.boot.cli.command.TestCommand; import org.springframework.boot.cli.command.tester.TestResults; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** @@ -37,12 +38,11 @@ public class TestCommandIntegrationTests { @BeforeClass public static void cleanGrapes() throws Exception { GrapesCleaner.cleanIfNecessary(); - // System.setProperty("ivy.message.logger.level", "3"); } @Before public void setup() throws Exception { - System.setProperty("disableSpringSnapshotRepos", "true"); + System.setProperty("disableSpringSnapshotRepos", "false"); new CleanCommand().run("org.springframework"); } @@ -77,9 +77,9 @@ public class TestCommandIntegrationTests { TestCommand command = new TestCommand(); command.run("samples/nothing.groovy"); } - catch (RuntimeException e) { - assertEquals("Can't find samples/nothing.groovy", e.getMessage()); - throw e; + catch (RuntimeException ex) { + assertEquals("Can't find samples/nothing.groovy", ex.getMessage()); + throw ex; } } @@ -123,4 +123,14 @@ public class TestCommandIntegrationTests { assertTrue(results.wasSuccessful()); } + @Test + public void verifyFailures() throws Exception { + TestCommand command = new TestCommand(); + command.run("samples/failures.groovy"); + TestResults results = command.getResults(); + assertEquals(5, results.getRunCount()); + assertEquals(3, results.getFailureCount()); + assertFalse(results.wasSuccessful()); + } + }