Please see the update at the bottom!
I am setting up my framework and currently have 4 Tests. Individually they all run like a charm. However when I try to run all 4 in parallel (I have set up the Parallelizable attribute up correctly and am calling tests from different classes not within the same method) I am consistently getting several errors that seem to jump around each test. These are the messages that I am getting each run:
Again These objects are found when the tests are run individually. I am not sure what code I need to show in order to help. Please advise.
UPDATE** #Chris my suspicions are the same. I think my tests are confusing the same driver when looking for objects. If that is the case can someone please advise how to better handle this, my browser class is what is calling the driver.
public static class Browser
{
private static IWebDriver driver;
private static string baseURL = "someURL";
public static ISearchContext Driver { get { return driver; } }
internal static bool WaitUntilElementIsDisplayed(By element, int timeout)
{
for (int i = 0; i < timeout; i++)
{
if (ElementIsDisplayed(element))
{
return true;
}
Thread.Sleep(1000);
}
return false;
}
internal static IWebElement FindElement(By by)
{
return driver.FindElement(by);
}
public static bool ElementIsDisplayed(By element)
{
var present = false;
driver.Manage().Timeouts().ImplicitlyWait(System.TimeSpan.FromSeconds(0));
try
{
present = driver.FindElement(element).Displayed;
}
catch (NoSuchElementException)
{ }
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
return present;
}
public static void Initialize()
{
var options = new InternetExplorerOptions();
options.IntroduceInstabilityByIgnoringProtectedModeSettings = true;
options.EnsureCleanSession = true;
options.IgnoreZoomLevel = true;
driver =
new InternetExplorerDriver(
#"C:Myfilepath",
options, TimeSpan.FromMinutes(10));
Goto("");
}
public static void CleanUp()
{
driver.Close();
driver.Quit();
}
public static void Goto(string URL, bool userBaseURL = true)
{
if (userBaseURL)
driver.Navigate().GoToUrl(string.Format("{0}/{1}", baseURL, URL));
else
driver.Navigate().GoToUrl(URL);
}
}
Newest Update: per the recommendation I have removed the static references but could someone help me with the syntax on creating an instance of the driver within my current code
public class Pages
{
private T GetPage<T>() where T : new()
{
var page = new T();
PageFactory.InitElements(Browser.Driver, page);
return page;
}
public LoginPage Login
{
get { return GetPage<LoginPage>(); }
}
public RegisterPage Register
{ get { return GetPage<RegisterPage>(); } }
public SearchPage Search
{ get { return GetPage<SearchPage>(); } }
}
I am not sure how to create an instance of Browser.Driver Please help!
Remove all references to "static" in your class and create an instance of the class in each test to fix your issue.
...Now change your Page class to accept the driver in the constructor
public class Pages
{
private readonly ISearchContext _context;
public Pages(ISearchContext context)
{
_context = context;
}
private T GetPage<T>() where T : new()
{
var page = new T();
PageFactory.InitElements(_context, page);
return page;
}
public LoginPage Login
{
get { return GetPage<LoginPage>(); }
}
public RegisterPage Register
{ get { return GetPage<RegisterPage>(); } }
public SearchPage Search
{ get { return GetPage<SearchPage>(); } }
}
... then in your test method
var browser = new Browser();
var page = new Page(browser.Driver);
Sorry. Been away and noticed your updates.
I have a separate class helper that I use to return my web driver. I’m using chrome driver and (headless) unit driver, which on my machines polices requires several params to get it running, so a class in its own right makes senses to me. E.g. WebDriverHelper.java. This has several static methods that returns a new instance of the driver of interest.
E.g.
WebDriver myDriver = WebDriverHelper.ChromeDriver();
My ChromeDriver method returns a new driver.
E.g.
return new ChromeDriver;
If you need more detail, let me know and I’ll copy some of my classes when I get in work tomorrow.
Related
Initially I had this structure:
interface IFileBackup
{
void Backup();
}
class BackUpMechanism1 : IFileBackup
{
void Backup()
{
//Back it up
}
}
class BackUpMechanism2 : IFileBackup
{
void Backup()
{
//Back it up in another way
}
}
class Client
{
//Instantiation of both mechanisms
//
try
{
backUpMechanism1.Backup();
}
catch(Exception ex)
{
backupMechanism2.Backup();
}
}
I was told that this was not a very clean design and to redesign it using the decorator pattern. The client should not know about the two back up mechanisms but just call backup and then the first mechanism should try to back up the file and if that fails then use mechanism 2. However I don't understand how to use the decorator pattern because from my understanding it extends functionality but doesn't replace functionality - which is what I want... How do I archive that? I have tried the following:
interface IFileBackup
{
void Backup();
}
class BackupMechanism1 : IFileBackup
{
public void Backup()
{
try
{
Console.WriteLine("Trying to back up to the cloud...");
throw new Exception();
}
catch(Exception ex)
{
Console.WriteLine("Oops that failed. We need to back up locally instead...");
}
}
}
class BackupMechanism2 : IFileBackup
{
IFileBackup _fileBackup;
public BackupMechanism2(IFileBackup fileBackup)
{
_filebackup = fileBackup;
}
public void Backup()
{
//All examples I have seen does this. But doesn't make sense in my case?
_fileBackup.Backup();
Console.WriteLine("Backing up locally");
}
}
//The client does not care about how the backup is done
class Client
{
static void Main()
{
//This is not right, but not sure what I should do in the client.
BackupMechanism2 localBackup = new BackupMechanism2(new BackupMechanism1());
localBackup.Backup();
Console.Read();
}
}
So essentially what I want to achieve is to have two backup mechanisms. Have the client just say backup I don't care how. Let the first mechanism try it's backup method if that fails then try the second method. I'm trying to use the decorator pattern to extend(replace) the backup behaviour of the first mechanism if it fails. I'm struggling to come up with a design that makes sense.
A very clean approach of implementing this would be adding a composite IFileBackup taking an array of IFileBackup objects, and trying them one by one until a working solution is found:
class CompositeBackup {
private readonly IFileBackup[] chain;
public CompositeBackup(params IFileBackup[] chain) {
this.chain = chain.ToArray();
}
public void Backup() {
foreach (var backup in chain) {
try {
backup.Backup();
return;
} catch {
continue;
}
}
throw new InvalidOperationException();
}
}
Now the client simply does this:
IFileBackup backup = new CompositeBackup(
new BackupMechanism1()
, new BackupMechanism2()
);
backup.Backup();
If you later decide to add BackupMechanism3 and BackupMechanism4, the user would need to add another object to the chain of backups. The rest of the code would remain unchanged. In addition, backup mechanisms themselves would remain unaware of other mechanisms' existence, which also simplifies the code.
The decorator pattern, in this case, can be used to provide fallback implementations. You can find plenty of obvious examples in the .Net streams implementation.
So with that in mind, your code should look something like this:
class abstract BaseFileBackup
{
internal BaseFileBackup Fallback;
internal BaseFileBackup(BaseFileBackup fallback) { Fallback = fallback; }
internal BaseFileBackup() { }
internal abstract void DoBackupWork();
internal void Backup()
{
try { DoBackupWork(); }
catch { if(Fallback != null) Fallback.Backup(); else throw; }
}
}
class BackUpMechanism1 : BaseFileBackup
{
internal BackUpMechanism1 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism1 (): base() {}
internal void DoBackupWork()
{
//Back it up
}
}
class BackUpMechanism2 : BaseFileBackup
{
internal BackUpMechanism2 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism2 (): base() {}
internal void DoBackupWork()
{
//Back it up in another way
}
}
// and to call it
class Client
{
static void Main()=>
new BackupMechanism2(new BackupMechanism1()).Backup();
}
Decorator Pattern is the WRONG choice in this scenario.
The problem that you are dealing with here is
under condition x call one method
under condition y call a different method
...
This is the precondition for the Strategy Pattern, and your initial solution was quite close to that. The problem in my mind is that you are using an Exception to determine the program flow, which is a BAD thing to do: exceptions cost stack space, and they should only be thrown under EXCEPTIONAL circumstances. Whereas in your case, it is expected that a given strategy will not work
IFileBackupStrategy
{
bool Backup(File fileToBackup);
}
IFileBackupContext
{
File ForBackup { set; }
bool Backup();
}
class CloudBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
class LocalBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
public class FileBackupContext : IFileBackupContext
{
private IEnumerable<IFileBackupStrategy> _backupStrategies
public Context(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public File ForBackup { set; private get; }
public bool Backup()
{
bool successFlag;
foreach(var strategy in _backupStrategies)
{
successFlag = strategy.Backup(ForBackup);
if(successFlag) break;
}
return successFlag;
}
}
In this case, all that the client needs to be aware of is the IFileBackupContext, and not the strategy employed to do the saving.
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
void SomeMethodThatInvokesBackingUp()
{
_context.ForBackup = new File(/* */);
if(!_context.Backup())
{
Console.WriteLine("Failed to backup the file");
}
}
}
The beauty of this design is that you can add more IFileBackupStrategy implementations, register them with your DI Container and voila they are instantly available to the client without a single code change or the need for re-compilation (though that will ultimately depend upon how you are populating your DI Container)
The decorator pattern is a method of adhering to the O principle in SOLID: which is
Open for extension and closed for modification
This means that you would use the decorator pattern to decorate an existing class, one that should not be changed and yet does not exhibit the behaviour required. The clue is in the name of the pattern: Decorator adds something, it does not change anything.
The Decorator Pattern is a Structural Pattern, whereas the Strategy Pattern, and what you are looking for, is a Behavioural Pattern
This example can be extended of course to report back the strategy which was ultimately employed, and also (if required) any reasoning for why alternate strategies were not.
Edited: in response to Blindy's comment below. Here is the paradigm for the decorator pattern, which should demonstrate how it is not the correct pattern for this problem:
class Image
{
void Render() { /* */ }
}
class FramedImage : Image
{
private Image _originalImage;
public FramedImage(Image original) => _originalImage = original;
new public void Render()
{
/* code to render a frame */
_originalImage.Render();
}
}
Image originalImage = new Image();
Image framedImage = new FramedImage(originalImage);
Image toRender = originalImage;
toRender.Render() // Renders the original image
toRender = framedImage;
toRender.Render(); // Renders the original image in a frame
It should be observed that there is no need to assign each Image to the toRender variable, that is done solely to demonstrate that a decorator is a decorated.
As you can see from this example, the decorator pattern adds behaviour, and it also invokes the decorated item's behaviour.
Edited: Further to the question posed by DSF below. Here is the full listing for a console app demonstrating how to achieve this using Unity 5.8.6
The code takes advantage of the new Tuple from C# 7.0.
I've just used some random number generation to determine whether or not each strategy implementation succeeds in performing its task.
using System;
using System.Collections.Generic;
using System.IO;
using Unity;
using Unity.Injection;
namespace StrategyPattern
{
public interface IFileBackupContext
{
FileStream ForBackup { set; }
(bool success, string strategy) Backup();
}
public interface IFileBackupStrategy
{
(bool success, string name) Backup(FileStream fileToBackup);
}
internal class LocalBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if(_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
return (_success, "LocalBackUp");
}
}
internal class CloudBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if (_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
fileToBackup.Close();
return (_success, "CloudBackUp");
}
}
public class FileBackupContext : IFileBackupContext
{
private readonly IEnumerable<IFileBackupStrategy> _backupStrategies;
public FileBackupContext(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public FileStream ForBackup { set; private get; }
public (bool success, string strategy) Backup()
{
foreach (var strategy in _backupStrategies)
{
var (success, name) = strategy.Backup(ForBackup);
if (success) return (true, name);
}
return (false, "");
}
}
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
public void BackgUpMyFile()
{
_context.ForBackup = new FileStream("d:\\myfile", FileMode.OpenOrCreate);
(bool success, string strategy) = _context.Backup();
if (!success)
{
Console.WriteLine("Failed to backup the file");
return;
}
Console.WriteLine($"File backed up using [{strategy}] strategy");
}
}
public class Bootstrap
{
private readonly IUnityContainer _container;
public Bootstrap()
{
_container = new UnityContainer();
_container.RegisterType<IFileBackupContext, FileBackupContext>();
_container.RegisterType<IFileBackupStrategy, LocalBackUp>("local");
_container.RegisterType<IFileBackupStrategy, CloudBackUp>("cloud");
_container.RegisterType<MyBackupClient>();
_container.RegisterType<Func<IEnumerable<IFileBackupStrategy>>>(new InjectionFactory(c =>
new Func<IEnumerable<IFileBackupStrategy>>(() =>
new[]
{
c.Resolve<IFileBackupStrategy>("local"),
c.Resolve<IFileBackupStrategy>("cloud")
}
)));
}
public MyBackupClient GetClient() => _container.Resolve<MyBackupClient>();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press ESC to quit ...");
Console.WriteLine("Press any other key to try again.");
Console.WriteLine();
var client = new Bootstrap().GetClient();
do
{
client.BackgUpMyFile();
} while (Console.ReadKey().Key != ConsoleKey.Escape);
}
}
}
What I'm using:
Selenium WebDriver (v3.2.0)
NUnit (v3.6.0)
C#
I've found online how to run a single test using multiple browser types in parallel, my code is as follows and this works:
namespace MultipleBrowserTest
{
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(EdgeDriver))]
public class SiteLoadsTest<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver _driver;
[Test]
public void MultipleBrowserTests()
{
_driver = new TWebDriver();
_driver.Navigate().GoToUrl("https://google.com/");
Assert.AreEqual("https://google.com/", _driver.Url);
}
[TearDown]
public void FixtureTearDown()
{
_driver?.Quit();
if (_driver != null) _driver.Dispose();
}
}
}
However, I want to make this more maintainable so that every test class the QA doesn't have to format the class with the 'where...' part (public class SomeUITestClass<TWebDriver> where TWebDriver : IWebDriver, new()). I was looking at making the test inheriting a Browser class like this:
public class Browsers<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver Browser { get; set; }
public IWebDriver Driver
{
get
{
if (Browser == null)
{
throw new NullReferenceException(
"The WebDriver browser instance was not initialized.");
}
return null;
}
set { Browser = value; }
}
public void LaunchDriver()
{
Browser = new TWebDriver();
}
}
And editing my test to be like this:
namespace MultipleBrowserTest
{
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(EdgeDriver))]
public class SiteLoadsTest_InheritedBrowser : Browsers<>
{
[SetUp]
public void Setup()
{
LaunchDriver();
}
[Test]
public void MultipleBrowserTests()
{
Driver.Navigate().GoToUrl("https://google.com/");
Assert.AreEqual("https://google.com/", Driver.Url);
}
[TearDown]
public void FixtureTearDown()
{
Driver?.Quit();
if (Driver != null) Driver.Dispose();
}
}
}
However I don't know what to pass into Browsers<>. If I don't pass anything I get "Unexpected use of an unbound generic name". If I pass in IWebDriver I am getting 'IWebDriver' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TWebDriver' in the generic type or method 'Browsers'.
I've got to the extent of my C# skills (as a QA) and I'm not sure how to resolve this or even whether it's resolvable! Any help would be much appriciated.
So with the amazing help of a fellow QA, we've worked out how to do this using reflection. We do have to add the constructor for our test (see below the Test Class):
namespace MultipleBrowserTest
{
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(EdgeDriver))]
public class SiteLoadsTest_InheritedBrowser : Browsers_Reflection
{
public SiteLoadsTest_InheritedBrowser(Type type) : base(type)
{
}
[Test]
public void MultipleBrowserTests()
{
Driver.Navigate().GoToUrl("https://google.com/");
Driver.Url.ShouldContain("google");
}
}
}
And this is the Browser class that we'll keep in our framework:
namespace MultipleBrowserTest
{
public class Browsers_Reflection
{
public Browsers_Reflection(Type type)
{
Driver = (IWebDriver)Activator.CreateInstance(type);
}
private IWebDriver Browser { get; set; }
public IWebDriver Driver
{
get {
if (Browser == null)
throw new NullReferenceException(
"The WebDriver browser instance was not initialized.");
return Browser;
}
set { Browser = value; }
}
}
}
Edit: We are also looking at using UnityContainer which we were having issues with but have worked it out, here is the code:
namespace MultipleBrowserTest
{
public class Browsers_UnityContainer
{
public Browsers_UnityContainer(Type type)
{
_unityContainer.RegisterType(typeof(IWebDriver), type, new InjectionConstructor());
Browser = _unityContainer.Resolve<IWebDriver>();
}
private IWebDriver Browser { get; set; }
private readonly UnityContainer _unityContainer = new UnityContainer();
public IWebDriver Driver
{
get { return Browser; }
set { Browser = value; }
}
}
}
I have set up a testproject using NUnit and Selenium Webdriver of which you can find a shortened version below.
class ByHolder
{
public readonly string name, path;
public readonly Func<string, By> call;
public ByHolder(string name, string path, Func<string, By> call)
{
this.name = name;
this.path = path;
this.call = call;
}
}
class Page
{
private readonly List<ByHolder> LocatorList = new List<ByHolder>();
public Page()
{
SetUpList();
}
private void SetUpList()
{
AddLocator("Button0", "//button0", By.XPath);
AddLocator("Button1", "button1", By.Id);
...
}
public By Get(string locatorName)
{
var holder = LocatorList.FirstOrDefault(p => p.name.Equals(locatorName));
return holder?.call(holder.path);
}
public void AddLocator(string name, string path, Func<string, By> call)
{
LocatorList.Add(new ByHolder(name, path,call ));
}
}
class PersonelDriver : IWebDriver
{
IWebDriver driver = new FirefoxDriver();
Page page = new Page();
public void Click(string locatorName)
{
driver.FindElement(page.Get(locatorName)).Click();
}
...
}
[TestFixture]
class PageTest
{
private readonly PersonelDriver d = new PersonelDriver();
[Test]
public void ClickTest0()
{
d.Click("Button0");
}
[Test]
public void ClickTest1()
{
d.Click("Button1");
}
...
}
As you can hopefully see I tried implementing a shortened method with a minimum of variables to make longer testcases easier to read mainly for outsiders but also for me, for example.
d.Click("that");
d.EnterText("thisLocator","text");
d.WaitFor("somethingElse");
d.Click("this");
(After using Selenium for some time I find that things can become chaotic quite fast when repeatedly using the driver.FindElement... in the tests themselves.)
Even tough I'm happy with the shortened versions and readability, there is of course no autocomplete or check since i'm handling strings and not IWebElement objects or By references that have been named or put in a specific getter.
What I used to do was the following, but it just felt wrong:
class Locators
{
public By GetButton()
{
return By.Id("button");
}
...
}
I was wondering if there is a way to implement an autocomplete or some other check for the string values when adding for example d.Click("stringvalue");
Thank you in advance.
I am trying to figure out the reason why my unit test would fail when run together with other unit tests in the solution but pass when run alone. Can anyone show me what am I missing?
The SUT is a class called CompositeClient that is essentially a wrapper class around two other clients. It's main idea is to give priority to one of those clients to be called.
public class CompositeClient : IReceiverChannel
{
private static readonly List<IReceiverChannel> ReceiverChannels = new List<IReceiverChannel>();
public CompositeClient(IReceiverChannel priority, IReceiverChannel normal)
{
ReceiverChannels.Add(priority);
ReceiverChannels.Add(normal);
}
public async Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
var req = new List<Request>();
foreach (var channel in ReceiverChannels)
{
req.AddRange(await channel.ReceiveBatchAsync(batchSize - req.Count).ConfigureAwait(false));
if (req.Count >= batchSize)
{
break;
}
}
return req;
}
}
Running the unit test below with all the other unit tests in the solution yield me a failed result. But if I run this test alone, it will pass.
[TestMethod]
public async Task ReceivedRequestShouldComeFromPriorityClientFirst()
{
var normalPriorityClient = GetNormalClientMock();
var highPriorityClient = GetPriorityClientMock();
var compositeClient = new CompositeClient(highPriorityClient, normalPriorityClient);
var requests = await compositeClient.ReceiveBatchAsync(1);
requests.Should().HaveCount(1);
requests.First().Origin.Should().BeSameAs("priority");
normalPriorityClient.CallCount.Should().Be(1); // It will fail here with actual CallCount = 0.
highPriorityClient.CallCount.Should().Be(0);
}
private static ReceiverChannelMock GetNormalClientMock()
{
return new ReceiverChannelMock("normal");
}
private static ReceiverChannelMock GetPriorityClientMock()
{
return new ReceiverChannelMock("priority");
}
private class ReceiverChannelMock : IReceiverChannel
{
private readonly string name;
public ReceiverChannelMock(string name)
{
this.name = name;
}
public int CallCount { get; private set; }
public Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
this.CallCount++;
return Task.FromResult<IEnumerable<Request>>(
new List<Request>
{
new Request
{
Origin = this.name
}
});
}
}
Tools used:
Visual Studio 2013
.NET Framework 4.5.2
Resharper 9.2
FluentAssertion
As David pointed out, I overlooked the static field that I declared in the CompositeClient class. Removing the static keyword solved the issue.
I am breaking down the testing on this so that I have feature files for areas like Login, ResetPassword, ForgotPassword etc. Let's say I have the below example. I have an automation step creating a brand new user in CreateAccount.feature. That step is used multiple times within that Feature/Step Class without issue. But now I want the user to change their password so I create a new Feature File MyAccount.feature. When I copy the Given Statement in, it is found immediately. Then I add the code to click the reset password and continue on with the rest of the steps.
When I run the ResetPassword test, the automation creates the new user but when it get's to step 2, "When I Click Reset Password" it fails because it can't find the element. Since bindings are global, this strikes me odd. So what I did was take step "Given I have created my account" and renamed it and added to the other feature file/steps class and ran it again. It worked fine.
I am not sure why I can't share between steps. Any ideas?
Some updates showing more code...
CreateAccount.feature
scenario: Feature Create Account
Given I have created my account
-----------
CreateAccountsteps.cs
namespace Project
{
[Binding]
public class CreateAccount: BaseTestObject
{
[Given]
public void Given_I_have_created_my_account()
{
ConfigProperties.Environment = "Test";
TestDriver.goToUrl(ConfigProperties.StartUrl);
TestDriver.goToUrl(ConfigProperties.StartUrl + "Create/Account");
[followed by input for creating a user acct]
-------------------------------------------------
MyAccount.feature
scenario: Feature Change Password
Given I have created my account
When I Click Reset Password
...........
MyAccountSteps.cs
namespace Project
{
[Binding]
public class MyAccountSteps: BaseTestObject
{
[When]
public void When_I_click_Reset_Password()
{
On.MyHeaderPage.BtnResetPassword.Click();
}
[followed by rest of steps to change password]
BaseTestObject.cs
namespace Project
{
public class BaseTestObject
{
private IWebDriver seleniumDriver;
private IDriver testDriver;
[TestInitialize]
public virtual void Setup()
{
TestDriver.goToUrl(ConfigProperties.StartUrl);
}
[AfterScenario]
public void CleanUp()
{
if (seleniumDriver != null)
{
SeleniumDriver.Dispose();
seleniumDriver = null;
}
}
public IWebDriver SeleniumDriver
{
get
{
if (seleniumDriver == null)
{
seleniumDriver = GetDriver();
}
return seleniumDriver;
}
}
public IDriver TestDriver
{
get
{
if (testDriver == null)
{
testDriver = new UiDriver(SeleniumDriver);
}
return testDriver;
}
}
public CurrentPageObjectScope On
{
get
{
return new CurrentPageObjectScope(TestDriver);
}
}
public static String GetTimestamp()
{
return DateTime.Now.ToString("yyyyMMddhhmmssfff");
}
public static String GetTimestamp2()
{
return DateTime.Now.ToString("M/d/yyyy");
}
private IWebDriver GetDriver()
{
switch (ConfigProperties.Browser.ToLower())
{
case "firefox":
return new FirefoxDriver();
case "chrome":
ChromeOptions options = new ChromeOptions();
ChromeDriverService service = ChromeDriverService.CreateDefaultService(#"../Chrome/");
service.SuppressInitialDiagnosticInformation = true;
service.HideCommandPromptWindow = true;
options.AddArguments("test-type");
options.AddArgument("--start-maximized");
return new ChromeDriver(service, options);
case "ie":
case "internetexplorer":
return new InternetExplorerDriver(#"../IE/");
default:
throw new NotImplementedException("Unknown browser string in Config properties " + ConfigProperties.Browser);
}
}
Based on your updates it looks like you have named your when step incorrectly. You feature says:
scenario: Feature Change Password
Given I have created my account
When I Click Reset Password
but you step has the name When_I_click_My_Account
This seems wrong to me.
Really though we need more details (like the actual exception message) and perhaps some indication of what BaseTestObject looks like.
Resolved - In the BaseTestObject I changed the methods to static.