How can I create Scenario object in cucumber framework and keep alive through all test run?
First Class:
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import io.cucumber.java.en.Given;
public class TestStepDefinitionOne {
Scenario scenario;
#Before
public void keepScenario(Scenario scenario) {
this.scenario = scenario;
}
Given("First step")
public void first_step() {
// Some code
scenario.log("Some text");
}
Given("Second step")
public void second_step() {
// Some code
scenario.log("Some text");
}
}
Second Class:
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import io.cucumber.java.en.Given;
public class TestStepDefinitionTwo {
Scenario scenario;
#Before
public void keepScenario(Scenario scenario) {
this.scenario = scenario;
}
Given("First step")
public void first_step() {
// Some code
scenario.log("Some text");
}
Given("Second step")
public void second_step() {
// Some code
scenario.log("Some text");
}
}
If I create #Before method in each step definition class everything works fine.
My question: Is there any way to create Scenario object in one place (like Hooks class) and keep it alive through all test run?
Related
Is there anyway we can share data between different extensions in JUNIT 5 using store
Example
public class Extension1{
beforeAllCallback(){
getStore(GLOBAL).put(projectId,"112");
}
}
public class Extension2{
beforeTestExecutionCallback(){
System.out.println("projectId="+getStore(GLOBAL).get(projectId));
}
}
Yes, two extensions can share state via the Store as follows.
Note, however, that you may wish to store the shared state in the root context Store if you want the state to be accessible across test classes.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
#ExtendWith({ Extension1.class, Extension2.class })
public class Tests {
#Test
void test() {
// executing this results in the following being printed to SYS_OUT.
// PROJECT_ID=112
}
}
class Extension1 implements BeforeAllCallback {
public static final String PROJECT_ID = Extension1.class.getName() + ".PROJECT_ID";
#Override
public void beforeAll(ExtensionContext context) throws Exception {
context.getStore(Namespace.GLOBAL).put(PROJECT_ID, "112");
}
}
class Extension2 implements BeforeTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
System.out.println("PROJECT_ID=" + context.getStore(Namespace.GLOBAL).get(Extension1.PROJECT_ID));
}
}
Extent report version - 3.0
Language - Java and TestNG classes
I have a class - ExtentManager.java
package framewrk;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
public class ExtentManager {
private static ExtentReports extent;
private static ExtentTest test;
private static ExtentHtmlReporter htmlReporter;
private static String filePath = "./extentreport.html";
public static ExtentReports GetExtent(){
extent = new ExtentReports();
htmlReporter = new ExtentHtmlReporter(filePath);
// make the charts visible on report open
htmlReporter.config().setChartVisibilityOnOpen(true);
// report title
String documentTitle = prop.getProperty("documentTitle", "aventstack - Extent");
htmlReporter.config().setDocumentTitle(documentTitle);
}
public static ExtentTest createTest(String name, String description){
test = extent.createTest(name, description);
return test;
}
public static ExtentTest createTest(String name){
test = extent.createTest(name, "");
return test;
}
}
and 2 testNG classes as follows
TC1.java
package framewrk;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
public class TC1 {
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how fail works");
test.log(Status.INFO, "fail check started");
test.fail("Test fail");
}
#AfterClass
public void tear()
{
extent.flush();
}
}
TC2.java
package framewrk;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
public class TC2 {
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how pass works");
test.log(Status.INFO, "pass check started");
test.pass("Passed");
}
#AfterClass
public void tear()
{
extent.flush();
}
}
If run these 2 test cases, I am getting only last testcase result, for the 1st testcase result, it's not displayed on the extent report.
Note that there is not append parameter for extent report 3.0.
How to get all test case results on extent report?
In the above approach, you are creating a new extent report in each Class. That is why you are getting only the latest executed test result.
You can create a common superclass for both TC1 and TC2 classes. In the superclass you can create #AfterClass and #BeforeClass functions. Then it should work.
Hope it helps!
I got one approach that works well, 1st check if the extent object is already created? if yes then return the object without reinitialising the extent object, here is how it looks
Under the ExtentManager class [as shown in the question], add this code block
public static ExtentReports getInstance() {
if(extent == null) {
GetExtent();
}
return extent;
}
Now under your testNG tests, before class annotation, call the above method
#BeforeClass
public void setup(){
extent = ExtentManager.getInstance();
}
In your case ExtentManager.GetExtent() this method overrides the previously created report hence only the last test result shows up in report. Make sure this method is only called during the whole set of your test start, best way is to do it by implementing ITestListener
Use this method extent.flush() in #aftersuite. because this statement generates the result
{
public class TC1
{
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how fail works");
test.log(Status.INFO, "fail check started");
test.fail("Test fail");
}
#Test
public void OpenUT1(){
test = extent.createTest("Testing how pass works");
test.log(Status.INFO, "pass check started");
test.pass("Passed");
}
#aftersuite
public void tear()
{
extent.flush();
}
}
I have a static method that is mocked using PowerMock to throw an exception. (It deletes files.) Unfortunately, during my #After (after-each-test) method, I need to call this method without the mocks. How can I umock a method?
I don't see an equivalent to Mockito.reset(). [ Ref: mockito : how to unmock a method? ]
Example:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PathUtils.class) // Important: This class has a static method we want to mock.
public class CleaningServiceImplTest2 extends TestBase {
public static final File testDirPath = new File(CleaningServiceImplTest2.class.getSimpleName());
#BeforeClass
public static void beforeAllTests() throws PathException {
recursiveDeleteDirectory(testDirPath);
}
#AfterClass
public static void afterAllTests() throws PathException {
recursiveDeleteDirectory(testDirPath);
}
private File randomParentDirPath;
private CleaningServiceImpl classUnderTest;
#Before
public void beforeEachTest() {
randomParentDirPath = new File(testDirPath, UUID.randomUUID().toString()).getAbsoluteFile();
classUnderTest = new CleaningServiceImpl(randomParentDirPath);
}
#After
public void afterEachTest() throws PathException {
recursiveDeleteDirectory(randomParentDirPath);
}
public static void recursiveDeleteDirectory(File dirPath) throws PathException {
// calls PathUtils.removeFile(...)
}
#Test
public void run_FailWhenCannotRemoveFile() throws IOException {
// We only want to mock one method. Use spy() and not mockStatic().
PowerMockito.spy(PathUtils.class);
// These two statements are tightly bound.
PowerMockito.doThrow(new PathException(PathException.PathExceptionReason.UNKNOWN, randomParentDirPath, null, "message"))
.when(PathUtils.class);
PathUtils.removeFile(Mockito.any(File.class));
classUnderTest.run();
}
}
This took me a while to figure out, so I am answering my own question.
AFAIK, you need to "undo" each mock. Mockito.reset() will not work with Class<?> references. At the end of the test method, add:
// Undo the mock above because we need to call PathUtils.removeFile() within #After.
PowerMockito.doCallRealMethod().when(PathUtils.class);
PathUtils.removeFile(Mockito.any(File.class));
The only way you can undo mocking of a static method with PowerMock is when you mock a class at the beginning of a test and then undo the mock at the end of a test. It doesn't matter if you use SPY or a regular mocking.
Tested with:
"org.powermock" % "powermock" % "1.5" % Test,
"org.powermock" % "powermock-api-mockito" % "1.6.1" % Test,
Test class
package mytests;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.fest.assertions.Assertions.assertThat;
#RunWith(PowerMockRunner.class)
#PrepareForTest({StaticTest.class})
public class TestTest {
#Before
public void checkIfOriginalMethodGetsCalled() {
// PowerMockito.mockStatic(StaticTest.class); if you do this in #Before you are not going to be able to undo it
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
}
#Test
public void test1() {
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
}
#Test
public void test3_mocking() {
mock(); // mock or spy static methods in a test, not in #Before
Mockito.when(StaticTest.staticMethod()).thenReturn("MOCKED VALUE");
assertThat(StaticTest.staticMethod()).isEqualTo("MOCKED VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
undoMock(); // undo the mock at the end of each test, not in #After
}
private void mock() {
// PowerMockito.mockStatic(StaticTest.class); both, spy and mockStatic work ok
PowerMockito.spy(StaticTest.class);
}
private void undoMock() {
PowerMockito.doCallRealMethod().when(StaticTest.class);
assertThat(StaticTest.staticMethod()).isNull(); // the undo is going to work in the next test, not here yet.
}
#Test
public void test2() {
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
}
#After
public void checkIfOriginalMethodGetsCalled_AfterMockUndo() {
// undoMock(); in #After doesn't work with static methods
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
}
}
class StaticTest {
public static String staticMethod() {
return "ORIGINAL VALUE";
}
public static String otherStaticMethod() {
return "SPY TEST ORIGINAL";
}
}
Is there a way in JUnit to detect within an #After annotated method if there was a test failure or error in the test case?
One ugly solution would be something like that:
boolean withoutFailure = false;
#Test
void test() {
...
asserts...
withoutFailure = true;
}
#After
public void tearDown() {
if(!withoutFailuere) {
this.dontReuseTestenvironmentForNextTest();
}
}
This is ugly because one need to take care of the "infrastructure" (withoutFailure flag) in the test code.
I hope that there is something where I can get the test status in the #After method!?
If you are lucky enough to be using JUnit 4.9 or later, TestWatcher will do exactly what you want.
Share and Enjoy!
I extend dsaff's answer to solve the problem that a TestRule can not execute some code snipped between the execution of the test-method and the after-method. So with a simple MethodRule one can not use this rule to provide a success flag that is use in the #After annotated methods.
My idea is a hack! Anyway, it is to use a TestRule (extends TestWatcher). A TestRule will get knowledge about failed or success of a test. My TestRule will then scan the class for all Methods annotated with my new AfterHack annotations and invoke that methods with a success flag.
AfterHack annotation
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface AfterHack {}
AfterHackRule
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class AfterHackRule extends TestWatcher {
private Object testClassInstance;
public AfterHackRule(final Object testClassInstance) {
this.testClassInstance = testClassInstance;
}
protected void succeeded(Description description) {
invokeAfterHackMethods(true);
}
protected void failed(Throwable e, Description description) {
invokeAfterHackMethods(false);
}
public void invokeAfterHackMethods(boolean successFlag) {
for (Method afterHackMethod :
this.getAfterHackMethods(this.testClassInstance.getClass())) {
try {
afterHackMethod.invoke(this.testClassInstance, successFlag);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException("error while invoking afterHackMethod "
+ afterHackMethod);
}
}
}
private List<Method> getAfterHackMethods(Class<?> testClass) {
List<Method> results = new ArrayList<>();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(AfterHack.class)) {
results.add(method);
}
}
return results;
}
}
Usage:
public class DemoTest {
#Rule
public AfterHackRule afterHackRule = new AfterHackRule(this);
#AfterHack
public void after(boolean success) {
System.out.println("afterHack:" + success);
}
#Test
public void demofails() {
Assert.fail();
}
#Test
public void demoSucceeds() {}
}
BTW:
1) Hopefully there is a better solution in Junit5
2) The better way is to use the TestWatcher Rule instead of the #Before and #After Method at all (that is the way I read dsaff's answer)
#see
I don't know any easy or elegant way to detect the failure of a Junit test in an #After method.
If it is possible to use a TestRule instead of an #After method, one possibility to do it is using two chained TestRules, using a TestWatcher as the inner rule.
Example:
package org.example;
import static org.junit.Assert.fail;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class ExampleTest {
private String name = "";
private boolean failed;
#Rule
public TestRule afterWithFailedInformation = RuleChain
.outerRule(new ExternalResource(){
#Override
protected void after() {
System.out.println("Test "+name+" "+(failed?"failed":"finished")+".");
}
})
.around(new TestWatcher(){
#Override
protected void finished(Description description) {
name = description.getDisplayName();
}
#Override
protected void failed(Throwable e, Description description) {
failed = true;
}
})
;
#Test
public void testSomething(){
fail();
}
#Test
public void testSomethingElse(){
}
}
I have three programs,
first does a selenium test
import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;
import junit.framework.*;
public class MyTest extends SeleneseTestCase {
int flag_eco;
public void setUp() throws Exception {
setUp("http://www.mysite.com/", "*iexplore");
}
public void testMyTest() throws Exception {
selenium.open("/pages/static/homepage_logout.html");
selenium.type("username", "myuser");
selenium.type("password", "password");
selenium.click("//input[#value='LOGIN']");
selenium.waitForPageToLoad("30000");
selenium.click("Confirm");
selenium.waitForPageToLoad("30000");
selenium.click("link=Applications");
selenium.waitForPageToLoad("30000");
selenium.click("link=Journey");
selenium.waitForPageToLoad("30000");
selenium.click("link=Launch Application (MUST BE LOGGED IN)");
selenium.waitForPageToLoad("30000");
if((selenium.isTextPresent("Please enter one of the following:")))
{
System.out.println("Journey Working Fine");
flag_test= 0;
}
else
{
System.out.println("Journey Failed");
flag_test = 1;
}
selenium.selectFrame("topmenu");
selenium.click("link=Home");
}
public static Test suite() {
//method added
return new TestSuite(MyTest.class);
}
public void tearDown(){
//Added . Will be called when the test will complete
selenium.stop();
}
}
then a sendmail gettin the values from the selenium test
import java.util.*;
public class SendMail
{
public void send()
{
MyTest Test = new MyTest();
if (Test.flag_test==1)
{
System.out.println("Journey Failed");
}
else if(Test.flag_test==0)
{
System.out.println("Journey Working Fine");
}
}
}
main class calling both
import java.io.*;
import javax.servlet.*;
public class Test
{
public static void main(String args[])
{
MyTest tes = new MyTest();
junit.textui.TestRunner.run(tes.suite());
SendMail se = new SendMail();
se.send();
}
}
how do i pass the flag value from MyTest to SendMail
The flag should be public static (I don't see it defined in the code you provided) - i.e.
public class MyTest {
public static int flag;
// the rest of the code
}
in send() you can refer to it with MyTest.flag_test
Note, that this is not a good way of passing data, but in your case there isn't anything better.
I think you are doing something that shouldn't be done at all. Here's what I propose:
move the code that is changing the flag outside the test
include it in the test, in the appropriate place (as if it is there)
include it in SendMail as well.
Thus you won't need to invoke the test in order to obtain a flag.
Three ways of achieving this
1. Pass the test as parameter to SendMail (already mentioned)
2. Write a listener on test, (Observable pattern/ PropertyChangeSupport in java) and hook it up. (Best IMO)
3. Write to a Static object which acts as white board and read from there. ( a poor man's message queue)