I was wondering if anyone could assist in a Code Review
on my Specflow Page Object Model
code. I have included a small sample of the code I use, most of the pages follow identical patterns.
Step Definitions
[Binding]
public class LoginStepDefinitions
{
public LoginStepDefinitions(IWebDriver _driver)
{
driver = _driver;
}
static IWebDriver driver;
[Given(@"I browse to (.*)")]
public void GivenINavigateTo(string url)
{
driver.Navigate().GoToUrl(url);
}
[Given(@"I login as (.*?) with Password (.*)")]
public void GivenILoginAs(string username, string password)
{
new LoginPom(driver, username, password);
}
[Then(@"I should be logged in")]
public void ThenIShouldBeLoggedIn()
{
Assert.DoesNotThrow(delegate { driver.FindElement(By.Id("logoutButton")); } );
}
[Given(@"I go to (.*?) within the (.*?) Menu")]
[Then(@"I should have access to (.*?) within the (.*?) Menu")]
public void ThenIShouldHaveAccess(string submenu, string menu)
{
Assert.DoesNotThrow(delegate {
new HeaderPom(driver).selectMenuByName(menu).selectSubMenuByName(submenu);
});
}
}
Page Object Model
public class LoginPom : Pages
{
public class LoginCredentials
{
public string Username { get; set; }
public string Password { get; set; }
}
public static Dictionary<string, LoginCredentials> loginData = new Dictionary<string, LoginCredentials>
{
{ "Admin",
new LoginCredentials()
{
Username= "AdminUsername",
Password= "AdminPassword"
}
}
};
[FindsBy(How = How.Id, Using = "ctl00_mainContent_userLogin_UserName")]
private IWebElement UserNameTxt;
[FindsBy(How = How.Id, Using = "ctl00_mainContent_userLogin_Password")]
private IWebElement PasswordTxt;
[FindsBy(How = How.Id, Using = "ctl00_mainContent_userLogin_loginButton")]
private IWebElement LoginBtn;
public LoginPom(IWebDriver driver) : base(driver)
{
}
public LoginPom(IWebDriver driver, String username, String password) : base(driver)
{
setUsername(username).setPassword(password).submit();
}
public LoginPom setUsername(String username)
{
this.UserNameTxt.Clear();
this.UserNameTxt.SendKeys(username);
return this;
}
public LoginPom setPassword(String password)
{
this.PasswordTxt.Clear();
this.PasswordTxt.SendKeys(password);
return this;
}
public void submit()
{
this.LoginBtn.Click();
}
}
I'm using the ObjectContainer
feature of SpecFlow
to initialize my WebDriver
based on the tag(s)
applied to the test(s)
.
[BeforeScenario("Firefox")]
public void InitializeFirefoxWebDriver()
{
DbAccess entities = new DbAccess();
DesiredCapabilities capability = DesiredCapabilities.Firefox();
capability.Platform = new Platform(PlatformType.Any);
launchWebDriver(capability);
objectContainer.RegisterInstanceAs<DbAccess>(entities);
}
public void launchWebDriver(DesiredCapabilities capability)
{
string gridUrl = "http://127.0.0.1:4444/wd/hub/";
ScenarioInfo si = ScenarioContext.Current.ScenarioInfo;
if (si.Tags.Any(x => x.StartsWith("GridUrl=")))
{
gridUrl = ConvertToString(si.Tags.FirstOrDefault(x => x.StartsWith("GridUrl=")).Split('=')[1]);
}
var webDriver = new RemoteWebDriver(new Uri(gridUrl), capability);
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
objectContainer.RegisterInstanceAs<IWebDriver>(webDriver);
}
I'm currently in the process of switching companies so I'm wanting to make certain, that the code is as easy to interpret and maintain as possible.
Any feedback is greatly appreciated.