cleanup after execution of all tests ( spock framework ) - java

i'm looking for a solution that allow me to handle the setup and the cleanup of my test environment at the launch and the end of my test framework execution.
The setup is not a problem but the cleanup imply to know when the test framework has finished to work or the index of the current test in execution queue.
Has someone a solution to implement this?

You can use org.spockframework.runtime.extension.IGlobalExtension to achieve this, as Spock extensions have callbacks for both BEFORE all specs start, and AFTER all specs end.
public interface IGlobalExtension {
void start();
void visitSpec(SpecInfo spec);
void stop();
}
So, implement stop() in your case to do whatever you need to do.
Spock finds extensions via Java's ServiceLoader, so make sure to add a META-INF/services file (pre-Java9) or declare it in your module-info.java file (post Java9), as explained here: http://spockframework.org/spock/docs/1.1/extensions.html#_writing_custom_extensions

One solution is to create an abstract class that all your specs extend:
class AbstractSpec extends Specification
then inside AbstractSpec find out the classes that are going to be run(for example if you're using spring framework):
private static final synchronized TEST_CLASSES = new ClassPathScanningCandidateComponentProvider(false).with {
addIncludeFilter(new AssignableTypeFilter(AbstractSpec.class))
findCandidateComponents("com/example/test").findAll { it.beanClassName != AbstractSpec.class.canonicalName }
.collect { Class.forName(it.beanClassName) }
}
then inside AbstractSpec do the actual clean up after all classes are run:
def synchronized cleanupSpec() {
TEST_CLASSES.remove(getClass())
if (TEST_CLASSES.isEmpty()) {
// clean up here
}
}
The problem with this solution is that if you run a subset of tests or classes in your IDE; you might have all the test classes in the classpath so TEST_CLASSES won't be emptied so the clean up won't execute.

Related

Spring/JUnit - Run something before ANY tests

Does Spring or the JUnit runner have something that I can use to run code before running ANY tests?
The closest I've found is the #Rule and #ClassRule, which work on a class level.
I have a Docker #ClassRule which hosts an empty database for empty integration testing. With the #ClassRule, it restarts the container every time.
I'd prefer instead to just start it once when starting the tests (regardless if it's all tests or just a single one), runs the tests, then kill the container.
I've searched around, but I haven't found anything other than the class rule. Apologizes if I'm missing something obvious.
It appears that Spring and JUnit don't directly have anything to do this. After some more googling, I found a few bits that lead to some inspiration.
Making use of a custom rule extending ExternalResource (from JUnit), I'm kind of bastardizing it, but it does what I want:
public class MyRule extends ExternalResource {
static private MyRule instance;
static public MyRule get() {
if (instance == null) {
instance = new MyRule();
}
return instance;
}
private MyRule() {
// do init stuff
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// do shutdown stuff
});
}
}
The basic idea is that the rule is a singleton. In each class that might need it, I'd put an #ClassRule:
public class MyTest {
#ClassRule
private MyRule myRule = MyRule.get();
}
It'll lazy-initialize itself, which will do all of the setup needed. It'll also register a shutdown hook, which will then handle any after stuff.
With this pattern, it'll run code exactly once before any tests (that need this rule) run, and it'll perform shutdown code only at the very end after all tests have finished.
Note: It purposely doesn't override the before() and after() functions, because those are before and after each class. You could add things there if you wanted to do something in between classes as well.
Maybe what you are looking for are those 2 annotations :
#BeforeClass
#Before
#Before runs before each test while #BeforeClass runs only once
You can use it like this :
#Before
public void setUp(){
// start container here
}
You also have equivalent for after test : #After #AfterClass
You will find a great explanation here
Thanks

#DirtiesContext tears context down after every cucumber test scenario, not class

Integration test executed by cucumber tends to leave behind context that causes problems with subsequent tests. Obvious solution appeared to be Spring's #DirtiesContext, but instead of tearing down the context after all the cucumber features have been run, it does this after each and every scenario, thus making the test execution time rather lengthy.
Tried also with #TestExecutionListeners, but no luck.
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( classes = { MyApplication.class, MyTestComponent.class }, loader = SpringApplicationContextLoader.class )
#ActiveProfiles( { "test", "someotherprofile" } )
#DirtiesContext( classMode = DirtiesContext.ClassMode.AFTER_CLASS )
#WebIntegrationTest( randomPort = true )
public class StepDefs extends StepDefUtils {
// givens, whens, thens
Am I trying to use DirtiesContext in an unsupported way?
As previous answer said the scenarios get compiled and run as separate classes stopping DirtiesContext from working and there are no per feature hooks in cucumber for same reason.
Workaround is to put tags in scenarios and have a class with hook detect these and conditionally dirty the context during the afterTestClass method.
The tag lets you control when context gets dirtied for example if want each feature to have fresh context then mark last scenario with tag, or can have many time per feature as and when needed.
public class CucumberFeatureDirtyContextTestExecutionListener extends AbstractTestExecutionListener{
private static boolean dirtyContext = false;
#After("#DirtyContextAfter")
public void afterDirtyContext(){
dirtyContext = true;
}
#Override public void afterTestClass(TestContext testContext) throws Exception {
if (dirtyContext) {
testContext.markApplicationContextDirty(HierarchyMode.EXHAUSTIVE);
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE, TRUE);
dirtyContext = false;
}
}
}
Mark scenarios with tag
#DirtyContextAfter
Scenario: My scenario
On steps class register the listener with spring
#TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class, CucumberFeatureDirtyContextTestExecutionListener.class})
Make sure the listener is in cucumber glue so after hook is registerd
Could not get it working on beforeClass as the context is already set up so have to do on afterClass.
Cucumber test methods are compiled into different test classes so #DirtiesContext( classMode = DirtiesContext.ClassMode.AFTER_CLASS ) will be run after each test method.
Unfortunately I don't see any DirtiesContext mode which suits your needs.
I would search for some cucumber listener and manually make spring context dirty trough it.

getting TestNG to treat class variables like JUnit with Guice

I am trying to setup TestNG so that it gives me new instances of my class variable for each test (basically like JUnit). I need this as I intend to parallelize my tests at the method level. I have been experimenting with both standalone Guice and the built in Guice functionality that TestNG provides to try to accomplish this but I have had no luck. I know that I can use ThreadLocal, but calling .get() for every variable in the test is pretty unappealing. I am weary of using GuiceBerry as it does not really have a lot of updates/activity and it's last release is not even acquirable via Maven. I am pretty set on TestNG as for all the inconvenience this is causing me it still does a lot of great things. I am open to things other tools though to accomplish my goal. Basically I want things setup so the below tests would work consistently. Any help would be greatly appreciated.
// just has a variable thats a class called child with a simple string variable
// with a value of "original
Parent p;
#Test
public void sometest1(){
p.child.value = "Altered";
Assert.assertTrue(p.child.value.equals("Altered"));
}
#Test
public void sometest2(){
Assert.assertTrue(p.child.value.equals("original"));
}
TestNG doesn't create a new instance for each test. If you want such a behavior than I recommend creating separate test classes. e.g.:
public class SomeTest1 {
Parent p;
#Test
public void something(){
p.child.value = "Altered";
Assert.assertTrue(p.child.value.equals("Altered"));
}
}
public class SomeTest2 {
Parent p;
#Test
public void something(){
Assert.assertTrue(p.child.value.equals("original"));
}
}
Note that TestNG can run JUnit 3 and JUnit 4 tests (you might maintain a mixed suite depending on the style you want to use in a given test class).

Extending from Suite Runner vs BlockJUnit4Runner while defining some TestRules

I have a requirement to write many tests. I have extended Suite Runner of JUnit in order to be able to add new annotations where I can mention several Prerequisite classes which will be executed before any of the tests or setups get executed. My Typical test looks like this.
#RunWith(CustomSuiteRunner.class)
#BeforeSuite(Prerequisite.class)
#AfterSuite(CleanupOperations.class)
#Suite.SuiteClasses({
SimpleTests.class,
WeatherTests.class
})
public class SimpleSuite {
}
I have overridden public void run(final RunNotifier notifier) to add code the required code to trigger prerequisites and cleanup operations mentioned in BeforeSuite and AfterSuite annotation.
Now, I'm trying to find out how I can achieve the same by extending BlockJUnit4Runner? I can't find any method equivalent to run that starts the execution to override the behaviour. There is runChild which gets triggered before a child gets executed.
The reason I'm looking for this is I'm trying created several rules in an Interface and make my tests implement that so that they will be available, however as Interface elements are static and final JUnit is ignoring these. In another Question I asked today I got answer that I can make JUnit consider rules mentioned in an Interface by extending BlockJUnit4Runner and overriding getTestRules().
So, Here is what I'm trying find out.
Is it possible to extend BlockJUnit4Runner to make it take a list of tests and run them as suite and also run some code before any tests get execute and after all tests are executed?
How can I extend Suite Runner to consider TestRules defined in an implemented interface?
It is pretty much possible to extend BlockJUnit4Runner and make it take a list of tests and run them as suite with required test dependencies handled within the extended runChild() method
public class CustomRunner extends BlockJUnit4ClassRunner {
private List<String> testsToRun = Arrays.asList(new String[] { “sample1” });
public CustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
public void runChild(FrameworkMethod method, RunNotifier notifier) {
//Handle any dependency logic by creating a customlistener registering notifier
super.runChild(method,notifier);
}
}

Unit testing both the presence/absence of a library

The question: Is there a way I can use a ClassLoader to test both the presence and absence of the library I'm checking for?
I have a some code which will use a particular library if available, or fall back to some embedded code if not. It works fine but I'm not sure how to unit test both cases in the same run, or if it's even possible. At the moment, my unit tests only check one case because the library is either in the main classpath or it's not.
The code I use to check for the library availability is basically:
boolean available;
try {
Class.forName("net.sf.ehcache.CacheManager");
available = true;
} catch (ClassNotFoundException e) {
available = false;
}
I could potentially alter the way this is done, if it would make unit testing easier.
You are trying to do two things at once:
test the different implementations of your code, and
test that the correct implementation is selected based on the circumstances (or, more generally, that your app works regardless of whether or not the library in question is present).
Separating the two tasks into distinct tests simplifies the problem. Thus, I would implement the two versions of your code as two Strategies, and put the code which checks the classpath and creates the necessary strategy into a Factory (Method). Then both strategies can be unit tested independent of classloader and classpath settings:
interface MyStrategy {
public void doStuff();
}
class MyLibraryUsingStrategy implements MyStrategy {
public void doStuff() {
// call the library
}
}
class MyEmbeddedStrategy implements MyStrategy {
public void doStuff() {
// embedded code
}
}
In unit tests, you can simply create and test either of the concrete strategies:
#Test
void testEmbeddedStrategy() {
MyStrategy strategy = new MyEmbeddedStrategy();
strategy.doStuff();
// assert results
}
A simple factory method to create the appropriate strategy:
MyStrategy createMyStrategy() {
MyStrategy strategy;
try {
Class.forName("net.sf.ehcache.CacheManager");
strategy = new MyLibraryUsingStrategy();
} catch (ClassNotFoundException e) {
strategy = new MyEmbeddedStrategy();
}
return strategy;
}
Since the factory code is fairly trivial, you may even decide not to write automated tests for it. But at any rate, testing the factory is more (part) of an integration test than a unit test; you can simply put together different setups of your app - one with and the other without the library in question - and see that both work properly.

Categories