Improve test coverage

This commit improves the test coverage to add strict template assertion
for well known use cases. This allows to catch obvious template issues.
This commit is contained in:
Stephane Nicoll
2016-04-08 16:17:33 +02:00
parent 544f7482d3
commit 046e39f232
14 changed files with 378 additions and 114 deletions

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.generator
import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.SimpleInitializrMetadataProvider
import io.spring.initializr.test.generator.GradleBuildAssert
import io.spring.initializr.test.generator.PomAssert
import io.spring.initializr.test.generator.ProjectAssert
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
import org.junit.Before
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.mockito.ArgumentMatcher
import org.springframework.context.ApplicationEventPublisher
import static org.mockito.Matchers.argThat
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.times
import static org.mockito.Mockito.verify
/**
*
* @author Stephane Nicoll
*/
abstract class AbstractProjectGeneratorTests {
@Rule
public final TemporaryFolder folder = new TemporaryFolder()
protected final ProjectGenerator projectGenerator = new ProjectGenerator()
private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher)
@Before
void setup() {
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addDependencyGroup('test', 'web', 'security', 'data-jpa', 'aop', 'batch', 'integration').build()
applyMetadata(metadata)
projectGenerator.eventPublisher = eventPublisher
projectGenerator.tmpdir = folder.newFolder().absolutePath
}
protected PomAssert generateMavenPom(ProjectRequest request) {
def content = new String(projectGenerator.generateMavenPom(request))
new PomAssert(content).validateProjectRequest(request)
}
protected GradleBuildAssert generateGradleBuild(ProjectRequest request) {
def content = new String(projectGenerator.generateGradleBuild(request))
new GradleBuildAssert(content).validateProjectRequest(request)
}
protected ProjectAssert generateProject(ProjectRequest request) {
def dir = projectGenerator.generateProjectStructure(request)
new ProjectAssert(dir)
}
ProjectRequest createProjectRequest(String... styles) {
def request = new ProjectRequest()
request.initialize(projectGenerator.metadataProvider.get())
request.style.addAll Arrays.asList(styles)
request
}
protected void applyMetadata(InitializrMetadata metadata) {
projectGenerator.metadataProvider = new SimpleInitializrMetadataProvider(metadata)
}
protected verifyProjectSuccessfulEventFor(ProjectRequest request) {
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
}
protected verifyProjectFailedEventFor(ProjectRequest request, Exception ex) {
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
}
private static class ProjectGeneratedEventMatcher extends ArgumentMatcher<ProjectGeneratedEvent> {
private final ProjectRequest request
ProjectGeneratedEventMatcher(ProjectRequest request) {
this.request = request
}
@Override
boolean matches(Object argument) {
ProjectGeneratedEvent event = (ProjectGeneratedEvent) argument
return request.equals(event.projectRequest)
}
}
private static class ProjectFailedEventMatcher extends ArgumentMatcher<ProjectFailedEvent> {
private final ProjectRequest request
private final Exception cause
ProjectFailedEventMatcher(ProjectRequest request, Exception cause) {
this.request = request
this.cause = cause
}
@Override
boolean matches(Object argument) {
ProjectFailedEvent event = (ProjectFailedEvent) argument
return request.equals(event.projectRequest) && cause.equals(event.cause)
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.generator
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.springframework.core.io.ClassPathResource
import static io.spring.initializr.test.generator.ProjectAssert.DEFAULT_APPLICATION_NAME
import static io.spring.initializr.test.generator.ProjectAssert.DEFAULT_PACKAGE_NAME
/**
* Project generator tests for supported languages.
*
* @author Stephane Nicoll
*/
@RunWith(Parameterized.class)
class ProjectGeneratorLanguageTests extends AbstractProjectGeneratorTests {
@Parameterized.Parameters(name = "{0}")
public static Object[] parameters() {
Object[] java = ["java", "java"]
Object[] groovy = ["groovy", "groovy"]
Object[] kotlin = ["kotlin", "kt"]
Object[] parameters = [java, groovy, kotlin]
parameters
}
private final String language
private final String extension
private final String expectedExtension
ProjectGeneratorLanguageTests(String language, String extension) {
this.language = language
this.extension = extension
this.expectedExtension = extension + '.gen'
}
@Test
public void standardJar() {
def request = createProjectRequest()
request.language = language
generateProject(request).isGenericProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME,
language, extension)
}
@Test
public void standardWar() {
def request = createProjectRequest('web')
request.language = language
request.packaging = 'war'
generateProject(request).isGenericWarProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME,
language, extension)
}
@Test
public void standardMainClass() {
def request = createProjectRequest()
request.language = language
def project = generateProject(request)
project.sourceCodeAssert("src/main/$language/com/example/DemoApplication.$extension")
.equalsTo(new ClassPathResource("project/$language/standard/DemoApplication.$expectedExtension"))
}
@Test
public void standardTestClass() {
def request = createProjectRequest()
request.language = language
def project = generateProject(request)
project.sourceCodeAssert("src/test/$language/com/example/DemoApplicationTests.$extension")
.equalsTo(new ClassPathResource("project/$language/standard/DemoApplicationTests.$expectedExtension"))
}
@Test
public void standardServletInitializer() {
def request = createProjectRequest()
request.language = language
request.packaging = 'war'
def project = generateProject(request)
project.sourceCodeAssert("src/main/$language/com/example/ServletInitializer.$extension")
.equalsTo(new ClassPathResource("project/$language/standard/ServletInitializer.$expectedExtension"))
}
}

View File

@@ -18,66 +18,38 @@ package io.spring.initializr.generator
import io.spring.initializr.metadata.BillOfMaterials
import io.spring.initializr.metadata.Dependency
import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.SimpleInitializrMetadataProvider
import io.spring.initializr.test.generator.GradleBuildAssert
import io.spring.initializr.test.generator.PomAssert
import io.spring.initializr.test.generator.ProjectAssert
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.mockito.ArgumentMatcher
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.ApplicationEventPublisher
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import static org.hamcrest.CoreMatchers.containsString
import static org.junit.Assert.assertThat
import static org.junit.Assert.fail
import static org.mockito.Matchers.argThat
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.times
import static org.mockito.Mockito.verify
/**
* Tests for {@link ProjectGenerator}
*
* @author Stephane Nicoll
*/
class ProjectGeneratorTests {
@Rule
public final TemporaryFolder folder = new TemporaryFolder()
private final ProjectGenerator projectGenerator = new ProjectGenerator()
private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher)
@Before
void setup() {
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addDependencyGroup('test', 'web', 'security', 'data-jpa', 'aop', 'batch', 'integration').build()
applyMetadata(metadata)
projectGenerator.eventPublisher = eventPublisher
projectGenerator.tmpdir = folder.newFolder().absolutePath
}
class ProjectGeneratorTests extends AbstractProjectGeneratorTests {
@Test
void defaultMavenPom() {
def request = createProjectRequest('web')
generateMavenPom(request).hasNoRepository()
.hasSpringBootStarterDependency('web')
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
verifyProjectSuccessfulEventFor(request)
}
@Test
void defaultGradleBuild() {
def request = createProjectRequest('web')
generateGradleBuild(request)
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
verifyProjectSuccessfulEventFor(request)
}
@Test
@@ -85,7 +57,7 @@ class ProjectGeneratorTests {
def request = createProjectRequest('web')
generateProject(request).isJavaProject().isMavenProject().pomAssert()
.hasNoRepository().hasSpringBootStarterDependency('web')
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
verifyProjectSuccessfulEventFor(request)
}
@Test
@@ -554,14 +526,6 @@ class ProjectGeneratorTests {
.hasDependenciesCount(3)
}
@Test
void kotlinWar() {
def request = createProjectRequest('web')
request.language = 'kotlin'
request.packaging = 'war'
generateProject(request).isKotlinWarProject()
}
@Test
void invalidType() {
def request = createProjectRequest('web')
@@ -571,7 +535,7 @@ class ProjectGeneratorTests {
fail("Should have failed to generate project")
} catch (InvalidProjectRequestException ex) {
assertThat ex.message, containsString('foo-bar')
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
verifyProjectFailedEventFor(request, ex)
}
}
@@ -584,7 +548,7 @@ class ProjectGeneratorTests {
fail("Should have failed to generate project")
} catch (InvalidProjectRequestException ex) {
assertThat ex.message, containsString('foo-bar')
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
verifyProjectFailedEventFor(request, ex)
}
}
@@ -597,66 +561,7 @@ class ProjectGeneratorTests {
fail("Should have failed to generate project")
} catch (InvalidProjectRequestException ex) {
assertThat ex.message, containsString('foo-bar')
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
}
}
PomAssert generateMavenPom(ProjectRequest request) {
def content = new String(projectGenerator.generateMavenPom(request))
new PomAssert(content).validateProjectRequest(request)
}
GradleBuildAssert generateGradleBuild(ProjectRequest request) {
def content = new String(projectGenerator.generateGradleBuild(request))
new GradleBuildAssert(content).validateProjectRequest(request)
}
ProjectAssert generateProject(ProjectRequest request) {
def dir = projectGenerator.generateProjectStructure(request)
new ProjectAssert(dir)
}
ProjectRequest createProjectRequest(String... styles) {
def request = new ProjectRequest()
request.initialize(projectGenerator.metadataProvider.get())
request.style.addAll Arrays.asList(styles)
request
}
private void applyMetadata(InitializrMetadata metadata) {
projectGenerator.metadataProvider = new SimpleInitializrMetadataProvider(metadata)
}
private static class ProjectGeneratedEventMatcher extends ArgumentMatcher<ProjectGeneratedEvent> {
private final ProjectRequest request
ProjectGeneratedEventMatcher(ProjectRequest request) {
this.request = request
}
@Override
boolean matches(Object argument) {
ProjectGeneratedEvent event = (ProjectGeneratedEvent) argument
return request.equals(event.projectRequest)
}
}
private static class ProjectFailedEventMatcher extends ArgumentMatcher<ProjectFailedEvent> {
private final ProjectRequest request
private final Exception cause
ProjectFailedEventMatcher(ProjectRequest request, Exception cause) {
this.request = request
this.cause = cause
}
@Override
boolean matches(Object argument) {
ProjectFailedEvent event = (ProjectFailedEvent) argument
return request.equals(event.projectRequest) && cause.equals(event.cause)
verifyProjectFailedEventFor(request, ex)
}
}

View File

@@ -121,7 +121,7 @@ class ProjectAssert {
isKotlinProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME)
}
private ProjectAssert isGenericProject(String expectedPackageName, String expectedApplicationName,
ProjectAssert isGenericProject(String expectedPackageName, String expectedApplicationName,
String codeLocation, String extension) {
String packageName = expectedPackageName.replace('.', '/')
hasFile("src/main/$codeLocation/$packageName/${expectedApplicationName}.$extension",
@@ -137,14 +137,6 @@ class ProjectAssert {
isJavaWarProject(DEFAULT_APPLICATION_NAME)
}
ProjectAssert isGroovyWarProject() {
isGenericWarProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME, 'groovy', 'groovy')
}
ProjectAssert isKotlinWarProject() {
isGenericWarProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME, 'kotlin', 'kt')
}
ProjectAssert isGenericWarProject(String expectedPackageName, String expectedApplicationName,
String codeLocation, String extension) {
String packageName = expectedPackageName.replace('.', '/')

View File

@@ -16,6 +16,12 @@
package io.spring.initializr.test.generator
import java.nio.charset.Charset
import org.springframework.core.io.Resource
import org.springframework.util.StreamUtils
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertTrue
@@ -35,6 +41,17 @@ class SourceCodeAssert {
this.content = content
}
SourceCodeAssert equalsTo(Resource expected) {
def stream = expected.inputStream
try {
String expectedContent = StreamUtils.copyToString(stream, Charset.forName('UTF-8'))
assertEquals "Unexpected content for $name", expectedContent, content
} finally {
stream.close()
}
this
}
SourceCodeAssert hasImports(String... classNames) {
for (String className : classNames) {
contains("import $className")

View File

@@ -0,0 +1,12 @@
package com.example
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class DemoApplication {
static void main(String[] args) {
SpringApplication.run DemoApplication, args
}
}

View File

@@ -0,0 +1,16 @@
package com.example
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner)
@SpringApplicationConfiguration(classes = DemoApplication)
class DemoApplicationTests {
@Test
void contextLoads() {
}
}

View File

@@ -0,0 +1,13 @@
package com.example
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.context.web.SpringBootServletInitializer
class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.sources(DemoApplication)
}
}

View File

@@ -0,0 +1,12 @@
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@@ -0,0 +1,16 @@
package com.example;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
public class DemoApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -0,0 +1,13 @@
package com.example;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DemoApplication.class);
}
}

View File

@@ -0,0 +1,11 @@
package com.example
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
open class DemoApplication
fun main(args: Array<String>) {
SpringApplication.run(DemoApplication::class.java, *args)
}

View File

@@ -0,0 +1,16 @@
package com.example
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner::class)
@SpringApplicationConfiguration(classes = arrayOf(DemoApplication::class))
class DemoApplicationTests {
@Test
fun contextLoads() {
}
}

View File

@@ -0,0 +1,12 @@
package com.example
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.context.web.SpringBootServletInitializer
class ServletInitializer : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder) : SpringApplicationBuilder {
return application.sources(DemoApplication::class.java)
}
}