Skip to content

Latest commit

 

History

History
139 lines (107 loc) · 6.03 KB

testing.adoc

File metadata and controls

139 lines (107 loc) · 6.03 KB

Testing

Different classes exist to help writing tests for Recipes, Conditions and Actions.

Windows & Linux

Linebreaks, encoding and path separator do (most probably will) differ depending on the OS the tests and the application is executed on.

To make the tests and application run on Windows, Linux and OSX you must take precautions in some cases.

Ignoring Line separator in assertions

TestProjectContext

When testing Actions and Conditions you’ll need a initialized ProjectContext as test fixture. To avoid reading projects for testing from the filesystem the TestProjectContext can be used.

The TestProjectContext offers ways to create all kinds of ProjectContext instances initialized from resorces given as strings as if they were read from filesystem. Have a look at the API documentation for details.

  • Creates different pom.xml. A blank default, with given dependencies defined, from a given String or as Mockito mock

  • Provides a method to register additional ResourceWrapper for specialized resources

String sourceCode = "package com.acme.app;\npublic class MyClass {}";

ProjectContext projectContext = TestProjectContext.buildProjectContext() (1)
        .withBuildFileHavingDependencies("org.junit.jupiter:junit-jupiter-api:5.7.0") (2)
        .withJavaSources(sourceCode) (3)
        .build(); (4)

// Use ProjectContext to test Action or Condition
  1. Call TestProjectContext static builder method which will inject a mock for ApplicationEventPublisher

  2. Add required dependencies to the classpath (assume they’re needed). This will add a pom.xml declaring the provided dependencies.

  3. Add a new Java file with given source to src/main/java/com/acme/app/MyClass.java

  4. build and return the initialized ProjectContext.

ProjectContextFileSystemTestSupport

If you want to create a ProjectContext from filesystem, ProjectContextFileSystemTestSupport is your friend.
It assumes a directory testcode in the same module as the test resides in. The initial project is read from a given directory inside testcode, let’s say testcode/given/my-project. The resources are then copied to target/test-projects/my-project and the ProjectContext is created from this directory.

@Test
void someTest() {
    ProjectContext projectContext = ProjectContextFileSystemTestSupport
                                            .createProjectContextFromDir("boot-23-app");
    // modify ProjectContext
}

Copies all resources from ./testcode/given/boot-23-app to ./target/test-projects/boot-23-app and creates a ProjectContext from it.

RecipeIntegrationTestSupport

If you want to integration test a recipe against a project read from filesystem, RecipeIntegrationTestSupport can help you.

String applicationDir = "example-app"; (1)

RecipeIntegrationTestSupport.initializeProject(applicationDir)
        .andApplyRecipe("boot-2.4-2.5-datasource-initializer"); (2)

Path javaClass = RecipeIntegrationTestSupport.getResultDir(applicationDir).resolve("src/main/java/com/example/SomeJavaClass.java"); (3)

assertThat(javaClass).hasContent("..."); (4)
  1. Provide a project, here under ./testcode/example-app/given. This project will be copied to a clean dir target/test-projects/example-app

  2. Scan the copied project and apply the given recipe against it

  3. Retrieve the path to a resource after migration

  4. Verify the resource has expected content

IntegrationTestBaseClass

For end-to-end tests using the shell commands IntegrationTestBaseClass will be helpful.
These are the most complete tests but also the slowest.

Note
Currently these tests reside in spring-shell module.
public class MyFullBlownIntegrationTest extends IntegrationTestBaseClass {
    @Override
    protected String getTestSubDir() { (1)
        return "some-dir/project-dir"; (2)
    }

    @Test
    @Tag("integration")
    void migrateSomethingToSpringBoot() {
        initializeTestProject(); (3)
        scanProject(); (4)
        applyRecipe("initialize-spring-boot-migration"); (5)
        applyRecipe("migrate-x-to-boot"); (6)
        // simulate manual step
        replaceFile( (7)
                getTestDir().resolve("src/test/java/com/example/jee/app/PersonServiceTest.java"),
                getTestDir().resolve("manual-step/BootifiedPersonServiceTest.java")
        );
        String localBusinessInterface = loadJavaFile("com.example.jee.app.ejb.local", "ABusinessInterface"); (8)
        // verify @Local was removed
        assertThat(localBusinessInterface).doesNotContain("@Local"); (9)
        executeMavenGoals(getTestDir(), "clean", "package", "spring-boot:build-image"); (10)
        int port = startDockerContainer("jee-app:8.0.5-SNAPSHOT", 8080); (11)
        TestRestTemplate testRestTemplate = new TestRestTemplate(); (12)
        // Test Servlet
        String response = testRestTemplate.getForObject("http://localhost:" + port + "/HelloWorld", String.class); (13)
        assertThat(response).isEqualTo("Hello World!"); (14)
    }
}
  1. The getTestSubDir() method must be implemented.

  2. It must return the path to the test project in src/test/resources

  3. Copies test project from src/test/resources/some-dir/project-dir to target/sbm-integration-test/some-dir/project-dir

  4. Scans the copied test project, same as calling scan in CLI

  5. Apply the recipe initialize-spring-boot-migration, same as calling apply initialize-spring-boot-migration in CLI. Changes will be reflected in the filesystem after this call.

  6. Apply another recipe migrate-x-to-boot

  7. Replace a file, here because the Test needs to be migrated manually

  8. Load the content a Java file as String

  9. Assertions about the context of the Java file

  10. Call mvn clean package spring-boot:build-image in the test project

  11. Start the docker image from the last step containing the migrated Spring application

  12. Create a RestTemplate

  13. Use the RestTemplate to retrive some data from the migrated Spring application running in Docker

  14. Verify the response