How to use #DataProvider that is present in a different class?
I have created a different package and I have defined data providers next to each test cases. Please share how I may to use that in a different class.
You can use the dataProviderClass attribute of #Test:
public class StaticProvider {
#DataProvider(name = "create")
public static Object[][] createData() {
return new Object[][] {
new Object[] { new Integer(42) }
};
}
}
public class MyTest {
#Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
public void test(Integer n) {
// ...
}
}
Check the documentation for more details.
If you have unique dataProvider method name (createData), and if you choose not to give name after DataProvider annotation as below,
#DataProvider
public Object[][] createData(){
}
Then you can use the method name as below,
#Test(dataProvider = "createData", dataProviderClass = StaticProvider.class)
Related
public class HomePage {
public HomePage clickAboutUs1Link() {
aboutUs1.click();
return this;
}
public void clickAboutUs1Link() {
aboutUs1.click();
}
}
I will be calling the action method in my Test Class. So is there any advantage or disadvantage of using any one over the other when using Page Object Model with Selenium webdriver?
This question will be more clear if you had more methods. Consider those classes
public class HomePage {
public AboutUsPage clickAboutUsLinkAndGoToAboutUsPage() {
aboutUs1.click();
return new AboutUsPage();
}
public HomePage typeToField() {
aboutUs1.click();
return this;
}
public HomePage clickOnChecbox() {
aboutUs1.click();
return this;
}
}
class AboutUsPage {
public boolean isAboutUsPageDisplayed() {
return someElement.isDisplayed();
}
}
Now you can use method chaining in the test to create a flow
public class TestAboutUsLink {
boolean isDisplayed =
new HomePage()
.typeToField()
.clickOnChecbox()
.clickAboutUsLinkAndGoToAboutUsPage()
.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
And if every method didn't return anything
public class TestAboutUsLink {
HomePage homePage = new HomePage();
homePage.typeToField();
homePage.clickOnChecbox();
homePage.clickAboutUsLinkAndGoToAboutUsPage()
AboutUsPage aboutUsPage = new AboutUsPage();
boolean isDisplayed = aboutUsPage.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
This is subjective issue, but I find it clearer to have the test flow with implicit page objects creation (as far as the test concern) than breaking it to parts.
is there a way to map a DTO using MatStruct which have a few final data members as well and cannot have a default constructor , like :
public class TestDto {
private final String testName;
private int id;
private String testCase;
public TestDto(String testName) {
this.testName = testName;
}
public String getTestName() {
return testName;
}
public int getId() {
return id;
}
public String getTestCase() {
return testCase;
}
public void setId(int id) {
this.id = id;
}
public void setTestCase(String testCase) {
this.testCase = testCase;
}
}
please suggest how could this DTO be mapped using MapStruct.
You can use #ObjectFactory that would construct an instance of your DTO.
For example:
#Mapper
public interface MyMapper {
#ObjectFactory
default TestDto create() {
return new TestDto("My Test Name");
}
//the rest of the mappings
}
You can also enhance the #ObjectFactory to accept the source parameter, that you can use to construct the TestDto. You can even use a #Context as an Object Factory.
NB: You don't have to put the #ObjectFactory method in the same Mapper, or even a MapStruct #Mapper. You can put it in any class (or make it static) and then #Mapper(uses = MyFactory.class)
I want to intercept method named methodA with one arg which's type is String as blow, what should i do. How to use hasParameters() api?
public class Demo {
public static void main(String[] args) {
new ByteBuddy()
.subclass(A.class)
.method(named("methodA").and(hasParameters(?)))
}
static class A {
public void methodA() {
System.out.println("methodA() invoked.");
}
public void methodA(String arg) {
System.out.println("methodA(" + arg + ") invoked.");
}
}
}
For this you want the ElementMatchers.takesArguments(String.class) matcher.
So something like that:
Class<? extends A> loaded = new ByteBuddy().subclass(A.class)
.method(ElementMatchers.named("methodA").and(ElementMatchers.takesArguments(String.class)))
.intercept(MethodDelegation.to(Demo.class))
.make().load(Demo.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION).getLoaded();
A instance = loaded.getConstructor().newInstance();
instance.methodA("abc");
instance.methodA();
public class Demo {
static void intercept(String arg){
System.out.println("intercepted");
}
}
To clarify, you need to define a matcher (similar to a filter) to apply to methods. Create some constraint in the matcher so it will only match to some parameter structure you specify:
ElementMatcher<Iterable<? extends ParameterDescription>> matcher = parameterDescriptions -> {
for (ParameterDescription p : parameterDescriptions) {
if (p.getType().equals(TypeDescription.STRING.asGenericType()) && p.getIndex() == 0) return true;
}
return false;
};
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(SomeType.class)
.method(ElementMatchers.hasParameters(matcher))
.intercept(FixedValue.value("Hello World"))
.make()
.load(SomeType.class.getClassLoader(),
ClassReloadingStrategy.fromInstalledAgent());
A TestNG test class can become pretty bloated if every test uses its own DataProvider. Is there anyway to import these from another Java class (ie: one where constants are already declared)? I could not find any existing documentation.
You can create Data Providers in an another class (not in the same class having test methods) like below and refer it using dataProviderClass in Test annotation
import org.testng.annotations.DataProvider;
public class DataProviderClass { //Data Provider class
#DataProvider(name = "data-provider")
public static Object[][] dataProviderMethod() {
return new Object[][] { { "1" }, { "2" } };
}
}
TestClass.java
import org.testng.annotations.Test;
public class TestClass {
#Test(dataProvider = "data-provider", dataProviderClass = DataProviderClass.class)
public void testMethod(String data) {
System.out.println("Data is: " + data);
}
}
Say I have a scenario that uses steps that are contained in two different classes. Is there a way for both of them to have a handle to the same IWebDriver instance without going through ScenarioContext.Current["webdriverVariableName"]?
That's so ugly. Is there a cleaner way?
I was going to make a class with a public static IWebDriver property that gets assigned at the start of every scenario, so that all my steps could refer to it, but I don't think that will work when I start to run them in parallel, as each scenario would overwrite the global driver.
Specflow offers a Dependency Injection mecanism, so you could get your web driver instance injected in your steps.
See https://github.com/techtalk/SpecFlow/wiki/Context-Injection
See the "Avanced options" section.
I have just started using Specflow but this appears to work;
Create a class which takes IObjectContainer as a constructor and has a BeforScenario method to create the WebDriver instance;
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer _objectContainer;
public WebDriverSupport(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
var webDriver = DriverFactory.CreateDriver();
_objectContainer.RegisterInstanceAs<RemoteWebDriver>(webDriver);
}
}
Create your step classes with a constructor which take RemoteWebDriver;
[Binding]
public class POCSteps
{
private readonly IdlWebDriver _driver;
public POCSteps(IdlWebDriver driver)
{
_driver = driver;
}
}
Your steps steps will now have access to a fully instantiated WebDriver object
My tests, which are currently working fine running multithreaded webdriver instances, are using a base step definitions class to hold the driver instance. All step definitions inherit from this, so the driver is available to all steps..
namespace Project.StepDefinitions
{
[Binding]
public class BaseStepDefinitions
{
private const string CurrentPageKey = "Current.Page";
public static IWebDriver Driver { get; set; }
protected LogonPageModel LogonPage
{
get { return (LogonPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
protected RegisterPageModel RegisterPage
{
get { return (RegisterPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
}
}
//////////////
namespace SpecDriver.StepDefinitions
{
[Binding]
public class LoginSteps : BaseStepDefinitions
{
[Given(#"I navigate to the homepage")]
public void GivenINavigateToTheHomepage()
{
Driver.Navigate().GoToUrl(SettingsManager.BaseUrl);
}
}
}
etc etc...
Just create a new separated class with a static property that returns driver:
static class DriverProvider
{
private static IWebDriver _driver;
public static IWebDriver Driver
{
get
{
if (_driver == null)
{
_driver = new ChromeDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(40);
_driver.Manage().Window.Maximize();
}
return _driver;
}
}
}
Each time you will need to do something with driver, just call it in a such way:
SomeMethod(DriverProvider.Driver);
//
IWebelement e = DriverProvider.Driver.FindElement(By.XPath("you_XPath"));
e.Click();
// etc etc etc