We are using Selenium WebDriver to do UI testing, along with Cucumber. The language is Groovy, and the build tool is Gradle. Because it is expensive to create a WebDriver instance, we want to instantiate only one WebDriver instance and use it through all tests. However, we are having trouble to quit the driver properly after all tests are completed. Namely, the browser process spawned during the tests is still alive after running all the tests.
The code is currently structured like below.
// Test base class
class UITestBase {
WebDriver driver
static {
init()
}
static void init() {
// instantiate a webdriver
}
}
// Entry class of cucumber run
RunWith( Cucumber )
Cucumber.Options(...)
class CukeRunEntry {}
// Cucumber step class
class WhenSteps extends UITestBase {
#When(/^something happens$/)
void something_happens() {
// step implmentation
}
}
So, how can I call driver.quit() after all tests are finished but before gradle finishes the test task (we run the tests with ./gradlew test from command line)? I tried overriding the finalize() method, but that didn't help.
Thank you very much.
If I were you, I would prefer using SharedDriver that you can find here => https://github.com/cucumber/cucumber-jvm/blob/master/examples/java-webbit-websockets-selenium/src/test/java/cucumber/examples/java/websockets/SharedDriver.java
It makes life easier.
Edit
If you don't wish to use SharedDriver, you can add a block like below to the UITestBase class as illustrated in the question:
private static final Thread CLOSE_THREAD = new Thread() {
#Override
public void run() {
try {
driver.quit()
} catch ( Exception e ) {
}
}
}
static {
init()
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD)
}
The above code is essentially what's used in SharedDriver to ensure safe close of the WebDriver instance.
Related
I am running a test case where a mock's behavior is stubbed in the BeforeAll of a PER_CLASS test suite. The subject under test (in my boiled-down reproducer below) is a pool of worker threads which all interact with the mock. I then run multiple Test functions, each of which makes assertions about different expected effects of having run the thread pool. One such test verifies that the mock is invoked at least n times before a timeout. This test always fails because Mockito says there are 0 interactions with the mock. However, there are clearly interactions with the mock, because other test cases that rely on this interaction pass.
The Mockito docs say that mocks are thread-safe, but warns that multiple threads cannot stub and verify against a shared mock:
However Mockito is only thread-safe in healthy tests, that is tests without multiple threads stubbing/verifying a shared mock. Stubbing or verification of a shared mock from different threads is NOT the proper way of testing because it will always lead to intermittent behavior.
I'm not setting more than one stub and certainly not in multiple threads. When I debug my test case, it shows that the same thread actually performs both the stubbing and verification. I do not think I'm running afoul of this warning, then.
This SO answer suggests that there is a bug in Mockito (since 2017), but when I read through the Github issues, it looks like the issue is with argument captors, not with timeout or verify. I don't think this is the root cause, unless I'm overlooking something obvious.
I have written a reproducer below. It's a SpringBootTest case because that's the context in which I first encountered the issue, but I may try removing SpringBoot from the equation next. I have found a few interesting facts:
The verify step only fails in the PER_CLASS lifecycle; PER_METHOD works.
The PER_CLASS lifecycle test will succeed if I move the stubbing from the #BeforeClass to the #Test. (PER_METHOD works either way).
public class MyTest {
#Nested
#SpringBootTest(classes = MyBean.class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyPerClassTest {
#Autowired public MyBean bean;
#MockBean public Runnable runnable;
private final AtomicInteger counter = new AtomicInteger();
#BeforeAll
public void setup() {
Mockito.doAnswer(context -> {
counter.incrementAndGet();
return null;
}).when(runnable).run();
// Start a thread pool of workers that invoke the runnable.
bean.start();
}
#Test
public void isInvoked() {
// Fails: 0 interactions.
Mockito.verify(runnable, Mockito.timeout(10_000).atLeast(16)).run();
}
#Test
public void counterGoesUp() {
// Succeeds: the mock increments the counter as expected, because it is invoked.
Awaitility.await()
.atMost(FIVE_SECONDS)
.until(() -> counter.get() >= 16);
}
}
#Nested
#SpringBootTest(classes = MyBean.class)
#TestInstance(TestInstance.Lifecycle.PER_METHOD) // the default
public class MyPerMethodTest {
#Autowired public MyBean bean;
#MockBean public Runnable runnable;
private final AtomicInteger counter = new AtomicInteger();
#BeforeEach
public void setup() {
Mockito.doAnswer(context -> {
counter.incrementAndGet();
return null;
}).when(runnable).run();
// Start a thread pool of workers that invoke the runnable.
bean.start();
}
#Test
public void isInvoked() {
// Passes.
Mockito.verify(runnable, Mockito.timeout(10_000).atLeast(16)).run();
}
#Test
public void counterGoesUp() {
// Passes.
Awaitility.await()
.atMost(FIVE_SECONDS)
.until(() -> counter.get() >= 16);
}
}
}
I'm not sure why PER_CLASS fails. If anyone is familiar with why, please let me know. Thanks.
Inside a spock test we want to create a resource and make sure its disposed correctly regardless of the outcome of the test result.
We tried the approach below. But spock is not executing tests when the test code is wrapped inside a closure.
import spock.lang.Specification
class ExampleSpec extends Specification {
def wrapperFunction(Closure cl) {
try {
cl()
} finally {
// do custom stuff
}
}
def "test wrapped in closure"() {
wrapperFunction {
expect:
1 == 1
println "will not execute!"
}
}
}
What is the best approach on creating and disposing a resource inside a spock test.
setup() and cleanup() are not viable solutions since creating and disposing should be possible at arbitrary points inside the feature method.
You can use setup and cleanup block inside of the test case (feature method) like this:
class ReleaseResourcesSpec extends Specification {
void 'Resources are released'() {
setup:
def stream = new FileInputStream('/etc/hosts')
when:
throw new IllegalStateException('test')
then:
true
cleanup:
stream.close()
println 'stream was closed'
}
}
Code from the cleanup block is always executed although the test fails or if there is any exception. See the result of the above example:
So it is similar to setup() and cleanup() methods but in this case you can have different setup and clean up code for each feature method.
How can I run code in my #RunWith(SpringRunner.class) #SpringBootTest(classes = {...}) JUnit test before Spring starts?
This question has been asked several times (e.g. 1, 2) but was always "solved" by some configuration recommendation or other, never with a universal answer. Kindly don't question what I am about to do in that code but simply suggest a clean way to do it.
Tried so far and failed:
Extend SpringJUnit4ClassRunner to get a class whose constructor can run custom code before initializing Spring. Failed because super(testClass) must be called first thing and already does a whole lot of things that get in the way.
Extend Runner to get a class that delegates to SpringRunner instead of inheriting it. This class could run custom code in its constructor before actually instantiating the SpringRunner. However, this setup fails with obscure error messages like java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig. "Obscure" because my test has no web config and thus shouldn't meddle with sessions and cookies.
Adding an ApplicationContextInitializer that is triggered before Spring loads its context. These things are easy to add to the actual #SpringApplication, but hard to add in Junit. They are also quite late in the process, and a lot of Spring has already started.
One way to do it is to leave out SpringRunner and use the equivalent combination of SpringClassRule and SpringMethodRule instead. Then you can wrap the SpringClassRule and do your stuff before it kicks in:
public class SomeSpringTest {
#ClassRule
public static final TestRule TestRule = new TestRule() {
private final SpringClassRule springClassRule =
new SpringClassRule();
#Override
public Statement apply(Statement statement, Description description) {
System.out.println("Before everything Spring does");
return springClassRule.apply(statement, description);
}
};
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Test
public void test() {
// ...
}
}
(Tested with 5.1.4.RELEASE Spring verison)
I don't think you can get more "before" than that. As for other options you could also check out #BootstrapWith and #TestExecutionListeners annotations.
Complementing jannis' comment on the question, the option to create an alternative JUnit runner and let it delegate to the SpringRunner does work:
public class AlternativeSpringRunner extends Runner {
private SpringRunner springRunner;
public AlternativeSpringRunner(Class testClass) {
doSomethingBeforeSpringStarts();
springRunner = new SpringRunner(testClass);
}
private doSomethingBeforeSpringStarts() {
// whatever
}
public Description getDescription() {
return springRunner.getDescription();
}
public void run(RunNotifier notifier) {
springRunner.run(notifier);
}
}
Being based on spring-test 4.3.9.RELEASE, I had to override spring-core and spring-tx, plus javax.servlet's servlet-api with higher versions to make this work.
I'm creating custom task for gradle. I don't know how I can create task which will use my custom task class. Is it possible? I want to create this task for functional tests which will be runned on jenkins.
This is my custom task:
package pl.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class MyCustomTask extends DefaultTask {
public MyCustomTask() {
// do something
}
#TaskAction
def build() {
ant.echo(message: "only for tests")
}
}
And this is my test class:
package pl.gradle
import static org.junit.Assert.*
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.api.Project
import org.junit.Before;
import org.junit.Test
class MyCustomTaskTest {
private Project project;
def task
#Before
public void setUp() {
project = ProjectBuilder.builder().build()
task = project.task("build", type: MyCustomTask)
}
#Test
public void taskCreatedProperly() {
assertTrue(task instanceof MyCustomTask)
}
#Test
public void shouldRunTask() {
// task.execute() // how to run this task? I want to run build() method from MyCustomTask class which is #TaskAction
}
}
ProjectBuilder is meant for lower-level tests that don't execute tasks. Its sweet spot is testing plugins. In addition you'd write higher-level tests that execute real builds (and therefore also tasks). You'd typically use the Gradle tooling API to kick off these builds. Check out the tooling API samples in the full Gradle distribution.
Call Action.execute yourself for each of the task actions:
project.tasks.getByName("myTask").with { Task task ->
assertEquals task.group, 'My Group'
task.actions.each { Action action ->
action.execute task
}
}
I've previously mentioned this here: https://stackoverflow.com/a/63613564/410939
There is an application where users can provide custom groovy scripts. They can write their own functions in those scripts. I want to restrict people from using the 'synchronized' keyword as well as some other keywords in these scripts. For example it should not be possible to write a function like below.
public synchronized void test() {
}
I am creating a CompilerConfiguration and using the SecureASTCustomizer. However adding org.codehaus.groovy.syntax.Types.KEYWORD_SYNCHRONIZED to the list of black listed tokens doesn't seem to do the job. (if I add org.codehaus.groovy.syntax.Types.PLUS it's preventing the usage of '+' within scripts.. but doesn't seem to do the job for synchronized)
Any ideas on how to achieve this ...
You can do something like this:
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.syntax.SyntaxException
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.classgen.GeneratorContext
class SynchronizedRemover extends org.codehaus.groovy.control.customizers.CompilationCustomizer {
SynchronizedRemover() {
super(org.codehaus.groovy.control.CompilePhase.CONVERSION)
}
void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
classNode.methods.each { mn ->
if (mn.modifiers & 0x0020) { // 0x0020 is for synchronized
source.addError(new SyntaxException("Synchronized is not allowed", mn.lineNumber, mn.columnNumber))
}
}
}
}
def config = new CompilerConfiguration()
config.addCompilationCustomizers(new SynchronizedRemover())
def shell = new GroovyShell(config)
shell.evaluate '''
class Foo { public synchronized void foo() { println 'bar' } }
'''
The idea is to create a compilation customizer that checks generated classes and for each method, add an error if the synchronized modifier is present. For synchronized block inside methods, you can probably use the SecureASTCustomizer with a custom statement checker.