How to inject a Drone instance without managing its lifecycle? - arquillian-drone

I have a Graphene Page Object.
#Location("/page")
public class MyPage {
#Drone
private WebDriver driver;
// page methods using the driver
}
And a Test Class that uses the page object.
#RunWith(Arquillian.class)
public class MyTest {
#Test
public void test(#InitialPage MyPage page) {
// use page & assert stuff
}
#Test
public void anotherTest(#InitialPage MyPage page) {
// use page & assert stuff even harder
}
}
Now, I've decided that MyTest should use method scoped Drone instances. So I add...
public class MyTest {
#Drone
#MethodLifecycle
private WebDriver driver;
Now when I run the test I get two browsers and all tests end with errors. Apparently this lifecycle management is treated as a qualifier too.
Yes, adding #MethodLifecycle in MyPage too helps. But this is not a solution - a page shouldn't care about this and should work in any WebDriver regardless of its scope. Only tests have the knowledge to manage the drone lifecycles. A page should just use whatever context it was invoked in. How can I achieve that?

This may be the answer:
public class MyPage {
#ArquillianResource
private WebDriver driver;
But I'm afraid that this skips some Drone-specific enriching. Also not sure if it will correctly resolve when there are multiple Drone instances.

Related

I am getting null pointer exception for webelement defined under #FindBy annotation in page factory model

I'm new in Selenium learning. I'm getting null pointer exception when I try to use web element - Milestone_Tile_Text.click; in my code but it works fine when I use
LoginTestScript.fd.findElement(By.linkText("Milestone")).click();
Please see below code I have used PageFactory.initElements as well but not sure how to solve this error.
public class MilestoneTileModel
{
GenerateTestData objtestdata = new GenerateTestData() ;
public MilestoneTileModel() //constructor
{
PageFactory.initElements(LoginTestScript.fd, this);
}
#FindBy(xpath="//a[text()='Milestone']")
WebElement Milestone_Tile_Text;
public void Milestone_Tile_Click()
{
Milestone_Tile_Text.click();
LoginTestScript.fd.findElement(By.linkText("Milestone")).click();
LoginTestScript.fd.findElement(By.xpath("//*#id='CPH_btnAddNewMilestoneTop']")).click();
}
}
Timing issues might occur more often when you use an init method.
The timing issue is when you init an element the driver immediately try to find the elements, on failure you will get no warning but the elements will refer null.
The above can occur for example because the page was not fully rendered or the driver see an older version of the page.
A fix can be to define the elements as a property and on the get of the property use the driver to get the element from the page
Please note that selenium does not promise the driver sees the latest version of the page so even this might break and on some situations a retry will work.
First problem what I see: You didn't set LoginTestScript
Following documentation at first you need to set PageObject variable:
GoogleSearchPage page = PageFactory.initElements(driver, GoogleSearchPage.class);
The best way to rich that point is separate Page Object Model and scenario scipt
You fist file POM should contain:
LoginTestPOM
public class LoginTestPOM {
#FindBy(xpath="//a[text()='Milestone']")
WebElement MilestoneTileText;
public void clickMilestoneTitleText(){
MilestoneTitleText.click();
}
}
TestScript
import LoginTestPOM
public class TestLogin {
public static void main(String[] args) {
// Create a new instance of a driver
WebDriver driver = new HtmlUnitDriver();
// Navigate to the right place
driver.get("http://www.loginPage.com/");
// Create a new instance of the login page class
// and initialise any WebElement fields in it.
LoginTestPOM page = PageFactory.initElements(driver, LoginTestPOM.class);
// And now do the page action.
page.clickMilestoneTitleText();
}
}
This is basis of Page Object Pattern.
NOTE: I'm writing that code only in browser so it could contain some mistakes.
LINK: https://github.com/SeleniumHQ/selenium/wiki/PageFactory
The "ugly" solution without page object pattern is:
UglyTestScript
public class UglyTestLogin {
public static void main(String[] args) {
// Create a new instance of a driver
WebDriver driver = new HtmlUnitDriver();
// Navigate to the right place
driver.get("http://www.loginPage.com/");
// DON'T create a new instance of the login page class
// and DON'T initialise any WebElement fields in it.
// And do the page action.
driver.findElement(By.xpath("//a[text()='Milestone']").click()
}
}

Calling data from one class to another class - framework for JUnit

Please forgive me as I am still very new to the world of test automation. I have started out by using Selenium WebDriver with JUnit4, predominately on windows OS, although I have modified my scripts and ran them on Mac.
I want to be able to create a set of classes containing set data such as usernames, passwords, default url . Perhaps even calling them from an excel file, but for now Im happy to store the data in classes and then pass that data into other test classes. Im guessing this would be a framework of some sort.
Currently I am writing classes that all begin with something like:
public class ExampleSQATest{
public static Chromedriver chrome;
#BeforeClass
public static void launchBrowser(){
System.setProperty("webdriver.chrome.driver", "chromedriver/chromedriver.exe");
chrome = new ChromeDrievr();
}
#Test
public void aLogin(){
chrome.manage().window().maximize();
chrome.navigate().to("http://mydummywebsite.com");
new WebDriverWait(chrome, 10).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector
("input#UserName")));
WebElement username = chrome.findElementByCssSelector("input#UserName");
username.sendKeys("username");
WebElement password = chrome.findElementByCssSelector("input#Password");
password.sendKeys("password");
WebElement submit = chrome.findElementByCssSelector("input[type='submit']");
submit.click();
}
}
I will then proceed to write further test methods which requires entering data, but I'd like to be able to call this data from somewhere else that is already predefined.
Can anyone provide any suitable suggestions to investigate so I can learn. Something that is a guide or tutorial. Nothing too advanced, just something that helps me get started by advising me how to set a class of methods to be called by other classes and how it all links together as a framework.
Many thanks in advance.
One way to do this
public abstract class TestBase
{
private readonly INavigationManager navMgr;
private readonly IWindowNavigator windowNav;
private readonly ILoginManager loginMgr;
// All your stuff that is common for all the tests
protected TestBase()
{
this.navMgr = WebDriverManager.Get<INavigationManager>();
this.windowNav = WebDriverManager.Get<IWindowNavigator>();
this.loginMgr = WebDriverManager.Get<ILoginManager>();
}}
[TestFixture]
internal class QueriesTest : TestBase
{
private QueryTests queryTests;
[SetUp]
public void Setup()
{
this.queryTests = WebDriverManager.Get<QueryTests>();
// all the stuff you run specific before tests in this test class.
}
}
Assuming you have created test classes in webdriver-junit4, Use following two classes to call your test classes (Note-Import junit annotations)
1)Create test suite class as -
#RunWith(Suite.class)
#Suite.SuiteClasses({
YourTestClass1.class,
YourTestClass2.class,[you can add more tests you have created...]
})
public class TestSuiteJU {
}
2)Create class to call suite created above as-
public class TestExecution {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(TestSuiteJU .class);
}
}

How to run all cucumber functional automated test cases in single browser

I am new to cucumber testing as well as selenium testing.Please help me to run all cucumber test cases in single browser.As for now i am creating new WebDriver object in each cucumber step_def for feature file.
The solution is, Using / passing the same Web Driver object across your step_def. From your Question i assume, you have multiple Step Def files, If the stories are small and related put all of them in a single step_def file and have a single Web driver object. If it is not the case, invoke every step_def with a predefined Driver object that is globally declared in the configuration loader.
For using one browser to run all test cases use singleton design pattern i.e make class with private constructor and define class instance variable with a private access specifier.Create a method in that class and check that class is null or not and if it is null than create a new instance of class and return that instance to calling method.for example i am posting my code.
class OpenBrowserHelp {
private WebDriver driver;
private static OpenBrowserHelp browserHelp;
private OpenBrowserHelp() {
this.driver = new FirefoxDriver()
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.manage().window().maximize();
}
public static OpenBrowserHelp getOpenBrowserHelp() {
if (null == browserHelp) {
browserHelp = new OpenBrowserHelp();
}
return browserHelp;
}
WebDriver getDriver() {
return driver
}
void setDriver(WebDriver driver) {
this.driver = driver
}
public void printSingleton() {
System.out.println("Inside print Singleton");
}
Now, where ever you need to create browser instance than use
WebDriver driver = OpenBrowserHelp.getOpenBrowserHelp().getDriver();

Log4Net in App object?

I am getting started with Logging in a WPF desktop app, using Log4Net as the logging component. Here is my question: In a simple desktop app, is there any reason not to instantiate my logger as a property ov the App class (App.xaml.cs), like this?
public partial class App : Application
{
private static readonly ILog p_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public ILog Logger
{
get { return p_Logger; }
}
#endregion
}
}
That would allow me to invoke the logger
One reason springs to mind: since the App class's static constructor is the first bit of your code that will run, you will be instantiating the ILog instance before you've configured log4net. Therefore, you ILog instance won't be usable. Generally, you would instead do something like this:
public partial class App : Application
{
private static ILog log;
static App()
{
XmlConfigurator.Configure();
log = LogManager.GetLogger(typeof(App));
}
}
BTW, that MethodBase business really makes me cringe. Why not just use typeof(App)? You shouldn't be copy/pasting code without verifying it, anyway...and typeof(App) will work just fine with refactoring tools...
A couple of cases against using one global instance. By using one logger per class you get:
the benefit of logger hierarchies automatically following your class structure.
lesser coupling (your classes no longer have a dependency on the App class).
I did find a reason not to use a global logger in the App object. It works fine, but there is an advantage to getting a logger from within each class that will use it--It makes my log messages shorter and easier to write.
So I call GetLogger() in each class that will log, and I specify the name to be used for the logger. For example, in my OpenFile method, I can get a logger like this:
// Get logger
var logger = LogManager.GetLogger("OpenFile");
That relieves me of entering the class name in every error message I write. I still configure log4net in the App() constructor, since that only needs to be done once. That gives me a log message that looks like this:
2010-03-29 15:51:41,951 OpenFile [DEBUG]- Data file opened.
Kent's answer is still the accepted answer, but I figured I'd pass along what I had learned.

Android Unit Tests Requiring Context

I am writing my first Android database backend and I'm struggling to unit test the creation of my database.
Currently the problem I am encountering is obtaining a valid Context object to pass to my implementation of SQLiteOpenHelper. Is there a way to get a Context object in a class extending TestCase? The solution I have thought of is to instantiate an Activity in the setup method of my TestCase and then assigning the Context of that Activity to a field variable which my test methods can access...but it seems like there should be an easier way.
You can use InstrumentationRegistry methods to get a Context:
InstrumentationRegistry.getTargetContext() - provides the application Context of the target application.
InstrumentationRegistry.getContext() - provides the Context of this Instrumentation’s package.
For AndroidX use InstrumentationRegistry.getInstrumentation().getTargetContext() or InstrumentationRegistry.getInstrumentation().getContext().
New API for AndroidX:
ApplicationProvider.getApplicationContext()
You might try switching to AndroidTestCase. From looking at the docs, it seems like it should be able to provide you with a valid Context to pass to SQLiteOpenHelper.
Edit:
Keep in mind that you probably have to have your tests setup in an "Android Test Project" in Eclipse, since the tests will try to execute on the emulator (or real device).
Your test is not a Unit test!!!
When you need
Context
Read or Write on storage
Access Network
Or change any config to test your function
You are not writing a unit test.
You need to write your test in androidTest package
Using the AndroidTestCase:getContext() method only gives a stub Context in my experience. For my tests, I'm using an empty activity in my main app and getting the Context via that. Am also extending the test suite class with the ActivityInstrumentationTestCase2 class. Seems to work for me.
public class DatabaseTest extends ActivityInstrumentationTestCase2<EmptyActivity>
EmptyActivity activity;
Context mContext = null;
...
#Before
public void setUp() {
activity = getActivity();
mContext = activity;
}
... //tests to follow
}
What does everyone else do?
You can derive from MockContext and return for example a MockResources on getResources(), a valid ContentResolver on getContentResolver(), etc. That allows, with some pain, some unit tests.
The alternative is to run for example Robolectric which simulates a whole Android OS. Those would be for system tests: It's a lot slower to run.
You should use ApplicationTestCase or ServiceTestCase.
Extending AndroidTestCase and calling AndroidTestCase:getContext() has worked fine for me to get Context for and use it with an SQLiteDatabase.
The only niggle is that the database it creates and/or uses will be the same as the one used by the production application so you will probably want to use a different filename for both
eg.
public static final String NOTES_DB = "notestore.db";
public static final String DEBUG_NOTES_DB = "DEBUG_notestore.db";
First Create Test Class under (androidTest).
Now use following code:
public class YourDBTest extends InstrumentationTestCase {
private DBContracts.DatabaseHelper db;
private RenamingDelegatingContext context;
#Override
public void setUp() throws Exception {
super.setUp();
context = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_");
db = new DBContracts.DatabaseHelper(context);
}
#Override
public void tearDown() throws Exception {
db.close();
super.tearDown();
}
#Test
public void test1() throws Exception {
// here is your context
context = context;
}}
Initialize context like this in your Test File
private val context = mock(Context::class.java)

Resources