I'm using Selenide with Junit 5
Selenide 5.1.0
Junit 5.3.2
When I run tests with junit, same driver/browser is used for all tests. I want to create new WebDriver instance for each test.
I can call driver.quit() in AfterEach method. But I wanted to know is there any inbuilt method to handle the same in Selenide. So that I won't have to worry about driver initialization.
It should open a new driver for each Test and close after execution
It appears that there is no official JUnit Jupiter (JUnit 5) integration from Selenide:
https://github.com/selenide/selenide/issues/488
However, you could implement an Extension in JUnit Jupiter similar to the one available for Selenium:
https://bonigarcia.github.io/selenium-jupiter/
There are JUnit5 extensions in Selenide: https://github.com/selenide/selenide/tree/master/statics/src/main/java/com/codeborne/selenide/junit5
One of them, BrowserStrategyExtension, can reopen browser before every test.
You can implement Junit5 AfterEachCallback.
Here's an example:
public class CloseBrowserAfterEachTest implements AfterEachCallback {
#Override
public void afterEach(ExtensionContext extensionContext) throws Exception {
WebDriverRunner.closeWebDriver();
}
}
And then annotate your test classes (or your base test class) with #ExtendWith({CloseBrowserAfterEachTest.class})
Related
Currently going through the process of upgrading from Junit4 to Junit5 and running into a bit of a hurdle with something that used to work in Junit4.
Wondering if there is a way to access the #BeforeAll/#AfterAll (formerly #BeforeClass/#AfterClass) within a class which is also a #Suite
Example:
#Suite
#SelectClasses({
SquareService.class,
TriangleService.class
})
public class ShapeTestSuite {
#BeforeAll
public void beforeAll() {
Log.info("Shape Test Suite Start!");
}
#AfterAll
public void afterAll() {
Log.info("Shape Test Suite End!");
}
}
I've tried adding an extension to this class/suite, but that also does not seem to work. What am I missing? Any help would be greatly appreciated.
Thanks
#BeforeAll and #AfterAll runs before any execution of #Test, #TestFactory, etc.
So if you create one them you will see that your code will be run correctly.
#BeforeAll and #AfterAll are annotations from Jupiter, which is one (of many) JUnit 5 engines. #Suite, however, is independent and can run tests and test suites combined from any JUnit 5 engine. That’s why you cannot use a before-all method in a suite class.
I have setup an embedded mongo via flapdoodle (de.flapdoodle.embed).
Quite a lot of mongo operations hence i would like to run all of them as a suite and setup the mongo just once in testsuite.
Now when i run the test cases via mvn install , it seems to run the test cases individually.
Is there a way to run test cases only from suite and not as a class.
baeldung.com describes the use of JUnit 5 Tags, which are very well suited for your case.
You can mark tests with two different tags:
#Test
#Tag("MyMongoTests")
public void testThatThisHappensWhenThatHappens() {
}
#Test
#Tag("MyTestsWithoutMongo")
public void testThatItDoesNotHappen() {
}
And execute either set in a suite, e.g.
#IncludeTags("MyMongoTests")
public class MyMongoTestSuite {
}
In your case, the tests could be categorized by whether Mongo is in the application context or not. So, theoretically, it might be possible to create a JUnit 5 Extension to add the tag. That would be the more complex solution though.
I'm using WireMock in my tests and have such a line of code:
#Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
I want to switch to JUnit 5. So I added the next dependency (using Gradle):
testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1')
But there are no suggestions when I'm trying to import #Rule annotation.
Do I need to add another module of JUnit dependency? Or are rules not supported in JUnit 5? If not, how can I replace #Rule annotation to make tests work again?
In a general way, what you did with #Rule and #ClassRule in JUnit 4 should be done with #ExtendWith and Extension that associated provide a very close feature in JUnit 5.
It works as standards JUnit lifecycle hooks but that it is extracted in a Extension class. And similarly to #Rule, as many Extensions as required may be added for a test class.
To handle the issue you have several possible approaches among :
keep the JUnit 4 way (JUnit 5 owns the JUnit Vintage part that allows to execute JUnit 3 or 4 tests).
rewrite the #Rule as an Extension.
do the actual processing done by WireMockRule (start the server, execute your tests and stop the server) in each test of class with #BeforeEach and #AfterEach hook methods.
use a third library that implements the equivalent of WireMockRule in the JUnit 5 Extension way such as https://github.com/lanwen/wiremock-junit5
Note that your issue already discussed in the JUnit 5 Issues.
JUnit 4 annotations #Rule and #ClassRule do not exist in JUnit 5. Basically there is a new extension model that can be used to implement extensions with the same functionality. These extensions can be used with the #ExtendWith annotation.
There is a limited migration support for a subset of JUnit 4 rules in the junit-jupiter-migrationsupport module. Unfortunately, it's only limited to subclasses of ExternalResource and Verifier.
Before wiremock has official support for JUnit you have some workarounds:
Run JUnit 4 tests side by side with JUnit 5 tests with the junit-vintage-engine.
Start and stop the server yourself in the test code.
Use a 3rd party extension like wiremock-junit5 or wiremock-extension.
There is now official support for JUnit 5 Jupiter from WireMock 2.31.0.
Docs here: http://wiremock.org/docs/junit-jupiter/
The https://github.com/webcompere/java-test-gadgets project lets you solve this in a couple of ways.
You can use its support for JUnit 4 rules via the DangerousRuleAdapter - which will attempt to turn any JUnit 4 rule into a Plugin:
#ExtendWith(PluginExtension.class)
public class DangerousRuleAdapterExampleTest {
#Plugin
private DangerousRuleAdapter<WireMockRule> adapter =
new DangerousRuleAdapter<>(new WireMockRule());
#Test
void theTest() {
// use wiremock rule here
WireMockRule rule = adapter.get();
}
The rule adapters cannot work with rules that inspect the test class or the test method, but make a good attempt at running the rule.
There's also support for running a rule around some code:
TemporaryFolder temporaryFolder = new TemporaryFolder();
// let's use this temp folder with some test code
executeWithRule(temporaryFolder, () -> {
// here, the rule is _active_
callSomethingThatUses(temporaryFolder.getRoot());
});
And you can easily create your own new JUnit 5 plugin by using the PluginExtension and TestResource.of
#ExtendWith(PluginExtension.class)
class TestResourceIsActiveDuringTest {
private WireMockServer server;
#Plugin
private TestResource someResource = TestResource.from(() -> server.start(),
() -> server.stop());
From the JUnit 5 user guide:
#Rule and #ClassRule no longer exist; superseded by #ExtendWith and #RegisterExtension. See also "Limited JUnit 4 Rule Support".
However, as pointed out by Tom, WireMock has full JUnit Jupiter support since version 2.31.0:
// New JUnit 5 extension
#WireMockTest
class DeclarativeWireMockTest {
#Test
void test_something_with_wiremock(WireMockRuntimeInfo wmRuntimeInfo) {
// The static DSL will be automatically configured for you
stubFor(get("/static-dsl").willReturn(ok()));
// Instance DSL can be obtained from the runtime info parameter
WireMock wireMock = wmRuntimeInfo.getWireMock();
wireMock.register(get("/instance-dsl").willReturn(ok()));
// Info such as port numbers is also available
int port = wmRuntimeInfo.getHttpPort();
// Do some testing...
}
}
For more information, please refer to the corresponding docs.
Could you please look at my problem and give any advice to its solving.
I use JUnit4 and selenium 2 WebDriver.
So, I have class to run JUnit suite:
#RunWith(Suite.class)
#Suite.SuiteClasses({className1.class, clasName2.class})
public class TestSuite
{
public static TestSuite suite()
{
TestSuite suite = new TestSuite();
suite.addTest(new JUnit4TestAdapter(className1.class));
suite.addTest(new JUnit4TestAdapter(className2.class));
return suite;
}
}
each class contains #Test method and extends BaseClass that sets in #BeforeClass parameters (through DesiredCapabilities) to run suite on BrowserStack machines:
public class MyTestBase{
static protected WebDriver driver;
private boolean acceptNextAlert = true;
protected static StringBuffer verificationErrors = new StringBuffer();
#BeforeClass
public static void setUp() throws Exception {
DesiredCapabilities capability = DesiredCapabilities.firefox();
capability.setPlatform(Platform.WINDOWS);
capability.setCapability("build", "JUnit - Sample");
capability.setCapability("acceptSslCerts", "true");
capability.setCapability("browserstack.debug", "true");
driver = new RemoteWebDriver(
new URL("http://username:accesskey#hub.browserstack.com/wd/hub"),
capability);
driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
}
/* other code */
}
So, could you please help me with the next:
1) I need to create configuration file and use its parameters to run my TestSuite on different browsers in BrowserStack. Any examples of .xml file to do it will be appreciated.
2) And also how do I need to modify my TestSuite.class to use .xml file parameters.
3) My TestSuite.class consists of many .class with #Test method in each. Each class extends MyTestBase.class where annotations #BeforeClass and #AfterClass are located, but when I run TestSuite new browser has been launched for each class in TestSuite and it's a very big problem for me. What can I do for running browser once for all #Test methods across all classes in TestSuite. I know that #BeforeClass works for all #Test methods inside one class, but what should be done if there are may classes? In TestNG there is #BeforeSuite solves this problem.
Sorry, for so many questions, but I've tried a lot and didn't succeed in this :(
Thanks a lot!
You asked a lot of questions concerning different topics. I will try to sort things out.
Reusing a browser and not opening a new one for every test class
This can only be achieved if you instantiate your WebDriver once and use that object in all your tests. So don't instantiate your browser in the #BeforeClass method of your tests.
How do you initialise your WebDriver?
In the very first test class of your test suite. That might be a dedicated test just for opening the browser. Or you could include this functionality in all of your test and have to check, if the browser had already been initialised or not.
How to reuse a WebDriver object and share it between test classes?
I'd propose to create a Singleton that stores a WebDriver object. This way all tests can access it. However, it takes some more effort to make this thread-safe - in case your run your tests in parallel.
Running your tests with different browsers
You should make your tests #Parameterized and expect a set of WebDriver objects as parameters to execute.
Combining both: Different browsers and reusing browsers between tests
This will likely lead to a point where you would like to define parameters for your test suite. However, in standard JUnit 4 you can't do this.
I recommend to use the ParameterizedSuite runner from this library.
I am having a problem, one test class seems to be interfering with the other in my test suite.
I have a suite, which executes two classes, one is called MergeTestSuite.java (which is another Suite), and the other is called RecordTest.java.
RecordTest extends one class already tested by MergeTestSuite.java
I created another suite as follows:
#RunWith(Suite.class)
#Suite.SuiteClasses( {
MergeTestSuite.class,
RecordTest.class
})
public class CoreTestSuite {
#BeforeClass
public static void install() throws Throwable {
RegistryUtils.cleanupResources();
}
}
Both MergeTestSuite.class and RecordTest.class run fine individually. If I run CoreTestSuite, the second test will fail, unless I remove MergeTestSuite.class from the list.
A Junit TestSuite provides extra features for multiple tests. For instance, you can control the order in which the tests run and you can also combine multiple test suites into another suite. I think this older doc from Junit 3.1.8 describes it best.