-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(#1014): Add a mechanism to provide a custom test case runner
- Loading branch information
Thorsten Schlathoelter
committed
Oct 12, 2023
1 parent
12aa556
commit d61cfed
Showing
11 changed files
with
259 additions
and
11 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
core/citrus-api/src/main/java/org/citrusframework/TestCaseRunnerProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.citrusframework; | ||
|
||
import org.citrusframework.context.TestContext; | ||
|
||
/** | ||
* Interface for providing TestCaseRunner. | ||
* | ||
* @author Thorsten Schlathoelter | ||
* @since 4.0 | ||
*/ | ||
public interface TestCaseRunnerProvider { | ||
/** | ||
* Creates a TestCaseRunner which runs the given {@link TestCase} and the given {@link TestContext}. | ||
* @param testCase | ||
* @param context | ||
* @return | ||
*/ | ||
TestCaseRunner createTestCaseRunner(TestCase testCase, TestContext context); | ||
|
||
/** | ||
* Creates a TestCaseRunner with the given {@link TestContext}. | ||
* @param context | ||
* @return | ||
*/ | ||
TestCaseRunner createTestCaseRunner(TestContext context); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
core/citrus-base/src/main/java/org/citrusframework/TestCaseRunnerFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.citrusframework; | ||
|
||
import org.citrusframework.context.TestContext; | ||
import org.citrusframework.exceptions.CitrusRuntimeException; | ||
import org.citrusframework.spi.ResourcePathTypeResolver; | ||
|
||
/** | ||
* Factory for creating {@link TestCaseRunner} instances. By default, it uses | ||
* Citrus' built-in runner, but it also offers the flexibility to replace the default runner with a | ||
* custom implementation. To do this, it leverages the Citrus {@link ResourcePathTypeResolver} | ||
* mechanism. | ||
* | ||
* To provide a custom runner, the following file needs to be added to the classpath: | ||
* <p> | ||
* <code> | ||
* 'META-INF/citrus/test/runner/custom' | ||
* </code> | ||
* </p> | ||
* The specified file must define the type of {@link TestCaseRunnerProvider} responsible for | ||
* delivering the custom test case runner. | ||
* | ||
* @author Thorsten Schlathoelter | ||
* @since 4.0 | ||
* @see TestCaseRunnerProvider | ||
*/ | ||
public class TestCaseRunnerFactory { | ||
|
||
|
||
/** The key for the default Citrus test case runner provider */ | ||
private static final String DEFAULT = "default"; | ||
|
||
/** The key for a custom test case runner provider */ | ||
private static final String CUSTOM = "custom"; | ||
|
||
/** Test runner resource lookup path */ | ||
private static final String RESOURCE_PATH = "META-INF/citrus/test/runner"; | ||
|
||
/** Default Citrus test runner from classpath resource properties. Non-final to support testing.*/ | ||
private ResourcePathTypeResolver typeResolver = new ResourcePathTypeResolver(RESOURCE_PATH); | ||
|
||
private static final TestCaseRunnerFactory INSTANCE = new TestCaseRunnerFactory(); | ||
|
||
private TestCaseRunnerFactory() { | ||
// Singleton | ||
} | ||
|
||
/** | ||
* @return the Citrus default test case runner. | ||
*/ | ||
private TestCaseRunnerProvider lookupDefault() { | ||
return typeResolver.resolve(DEFAULT); | ||
} | ||
|
||
/** | ||
* @return a custom test case runner provider or the default, if no custom runner provider exists. | ||
*/ | ||
private TestCaseRunnerProvider lookupCustomOrDefault() { | ||
try { | ||
return typeResolver.resolve(CUSTOM); | ||
} catch (CitrusRuntimeException e) { | ||
return lookupDefault(); | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Create a runner. | ||
* @param context | ||
* @return | ||
*/ | ||
public static TestCaseRunner createRunner(TestContext context) { | ||
TestCaseRunnerProvider testCaseRunnerProvider = INSTANCE.lookupCustomOrDefault(); | ||
return testCaseRunnerProvider.createTestCaseRunner(context); | ||
} | ||
|
||
/** | ||
* Create a runner. | ||
* @param testCase | ||
* @param context | ||
* @return | ||
*/ | ||
public static TestCaseRunner createRunner(TestCase testCase, TestContext context) { | ||
TestCaseRunnerProvider testCaseRunnerProvider = INSTANCE.lookupCustomOrDefault(); | ||
return testCaseRunnerProvider.createTestCaseRunner(testCase, context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
core/citrus-base/src/main/resources/META-INF/citrus/test/runner/default
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
type=org.citrusframework.DefaultTestCaseRunner$DefaultTestCaseRunnerProvider |
118 changes: 118 additions & 0 deletions
118
core/citrus-base/src/test/java/org/citrusframework/TestCaseRunnerFactoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package org.citrusframework; | ||
|
||
import static org.testng.Assert.assertEquals; | ||
import static org.testng.Assert.assertTrue; | ||
|
||
import org.citrusframework.context.TestContext; | ||
import org.citrusframework.spi.ResourcePathTypeResolver; | ||
import org.mockito.Mockito; | ||
import org.springframework.test.util.ReflectionTestUtils; | ||
import org.testng.Assert; | ||
import org.testng.annotations.Test; | ||
|
||
public class TestCaseRunnerFactoryTest { | ||
|
||
@Test | ||
public void testDefaultRunnerWithGivenContext() { | ||
TestContext testContext = new TestContext(); | ||
TestCaseRunner runner = TestCaseRunnerFactory.createRunner(testContext); | ||
assertEquals(runner.getClass(), DefaultTestCaseRunner.class); | ||
|
||
DefaultTestCaseRunner defaultTestCaseRunner = (DefaultTestCaseRunner) runner; | ||
assertEquals(defaultTestCaseRunner.getContext(), testContext); | ||
assertTrue(defaultTestCaseRunner.getTestCase() instanceof DefaultTestCase); | ||
} | ||
|
||
@Test | ||
public void testDefaultRunnerWithGivenTestCaseAndContext() { | ||
TestContext testContext = new TestContext(); | ||
TestCase testCase = new DefaultTestCase(); | ||
|
||
TestCaseRunner runner = TestCaseRunnerFactory.createRunner(testCase, testContext); | ||
assertEquals(runner.getClass(), DefaultTestCaseRunner.class); | ||
|
||
DefaultTestCaseRunner defaultTestCaseRunner = (DefaultTestCaseRunner) runner; | ||
assertEquals(defaultTestCaseRunner.getContext(), testContext); | ||
assertEquals(defaultTestCaseRunner.getTestCase(), testCase); | ||
} | ||
|
||
@Test | ||
public void testCustomRunnerGivenContext() { | ||
ResourcePathTypeResolver resolverMock = Mockito.mock(ResourcePathTypeResolver.class); | ||
|
||
Mockito.doReturn(new CustomTestCaseRunnerProvider()).when(resolverMock).resolve("custom"); | ||
TestCaseRunnerFactory instance = (TestCaseRunnerFactory) ReflectionTestUtils.getField( | ||
TestCaseRunnerFactory.class,"INSTANCE"); | ||
Assert.assertNotNull(instance); | ||
|
||
TestContext testContext = new TestContext(); | ||
|
||
Object currentResolver = ReflectionTestUtils.getField(instance, "typeResolver"); | ||
try { | ||
ReflectionTestUtils.setField(instance, "typeResolver", resolverMock); | ||
TestCaseRunner runner = TestCaseRunnerFactory.createRunner(testContext); | ||
|
||
assertEquals(runner.getClass(), CustomTestCaseRunner.class); | ||
|
||
CustomTestCaseRunner defaultTestCaseRunner = (CustomTestCaseRunner) runner; | ||
assertEquals(defaultTestCaseRunner.getContext(), testContext); | ||
|
||
} finally { | ||
ReflectionTestUtils.setField(instance, "typeResolver", currentResolver); | ||
} | ||
|
||
} | ||
|
||
@Test | ||
public void testCustomRunnerGivenTestCaseAndContext() { | ||
ResourcePathTypeResolver resolverMock = Mockito.mock(ResourcePathTypeResolver.class); | ||
|
||
Mockito.doReturn(new CustomTestCaseRunnerProvider()).when(resolverMock).resolve("custom"); | ||
TestCaseRunnerFactory instance = (TestCaseRunnerFactory) ReflectionTestUtils.getField( | ||
TestCaseRunnerFactory.class,"INSTANCE"); | ||
Assert.assertNotNull(instance); | ||
|
||
TestContext testContext = new TestContext(); | ||
TestCase testCase = new DefaultTestCase(); | ||
|
||
Object currentResolver = ReflectionTestUtils.getField(instance, "typeResolver"); | ||
try { | ||
ReflectionTestUtils.setField(instance, "typeResolver", resolverMock); | ||
TestCaseRunner runner = TestCaseRunnerFactory.createRunner(testCase, testContext); | ||
|
||
assertEquals(runner.getClass(), CustomTestCaseRunner.class); | ||
|
||
CustomTestCaseRunner defaultTestCaseRunner = (CustomTestCaseRunner) runner; | ||
assertEquals(defaultTestCaseRunner.getContext(), testContext); | ||
assertEquals(defaultTestCaseRunner.getTestCase(), testCase); | ||
|
||
} finally { | ||
ReflectionTestUtils.setField(instance, "typeResolver", currentResolver); | ||
} | ||
|
||
} | ||
|
||
private static class CustomTestCaseRunnerProvider implements TestCaseRunnerProvider { | ||
|
||
@Override | ||
public TestCaseRunner createTestCaseRunner(TestCase testCase, TestContext context) { | ||
return new CustomTestCaseRunner(testCase, context); | ||
} | ||
|
||
@Override | ||
public TestCaseRunner createTestCaseRunner(TestContext context) { | ||
return new CustomTestCaseRunner(context); | ||
} | ||
} | ||
|
||
private static class CustomTestCaseRunner extends DefaultTestCaseRunner { | ||
|
||
public CustomTestCaseRunner(TestContext context) { | ||
super(context); | ||
} | ||
|
||
public CustomTestCaseRunner(TestCase testCase, TestContext context) { | ||
super(testCase, context); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters