我是一名Specflow新手,刚刚开始,所以希望有人可以帮助我吗?这全可以归因于我自己对应该如何工作的误解,但是希望有人可以帮助我进步。
所以!我有一个正在处理的测试项目,它包含2个功能文件和2个Step类文件(以及使用POM的Pagefile)。
1。)ServiceSchedules.feature 2.)ServiceSchedulesSteps.cs 3.)Login.feature 4.)LoginPageSteps.cs
功能文件都共享一个步骤,“并且浏览器已关闭”,以在每种情况下关闭浏览器。这适用于Login.feature文件中的方案测试,但不适用于其他功能文件ServiceSchedules.feature中的方案测试,该步骤在此步骤中使用“ Driver.Dispose”失败。它返回以下错误;
System.NullReferenceException:对象引用未设置为 对象的实例。
我希望该步骤可以在功能文件之间共享? (也许不是我尝试的方式吗?)
作为旁注,我理解这不是最佳实践,因为我了解您可以使用挂钩,但是当我尝试使用AfterScenario Hook尝试在每次测试后关闭浏览器时遇到了另一个问题。当从的ServiceSchedules.feature文件运行相同的方案测试时,它返回了另一个错误(使用下面的相同代码)。
System.ArgumentException:定位器对象的SearchContext 不能为空参数名称:定位符
但是回到我当前的问题-这是我的文件; FeatureFile 1:LoginFeature
@All @Login
Feature: LoginPage
In order to use the Program
As a User
I want to be be able to see the login Page
Background:
Given I want to login
@Content
Scenario: LoginPageContent
When I view the Login Page
Then everything I need to login is present
And the browser is closed
@ErrorMessage
Scenario: InvalidLoginError
When I enter invalid Username of "!£$%^&*^%?["
And enter an invalid Password "£$%^&*£!"
And the submit button is pressed
Then an Invalid Name or Password error will display on a popup
And the browser is closed
@ErrorMessage
Scenario: NoLoginDetailsError
And I have not entered a username
And I have not entered a password
When the submit button is pressed
Then an error message will display under the username field of "The User name field is required."
And an error message will display under the password field of "The Password field is required."
And the browser is closed
LoginPageSteps.cs
using NUnit.Framework;
using OpenQA.Selenium;
using System;
using System.Threading;
using TechTalk.SpecFlow;
namespace Selenium.Services.SpecFlow2.SpecFlow.CodedSteps
{
[Binding]
public class LoginPageSteps
{
public IWebDriver Driver { get; set; }
[Given(@"I want to login")]
public void GivenIWantToLogin()
{
Driver = UserActions.IntializeDriver();
}
[Given(@"I have not entered a username")]
public void GivenIHaveNotEnteredAUsername()
{
var signinpage = new SignInPage(Driver);
Thread.Sleep(10);
signinpage.UserNameS.Clear();
}
[Given(@"I have not entered a password")]
public void GivenIHaveNotEnteredAPassword()
{
var signinpage = new SignInPage(Driver);
Thread.Sleep(10);
signinpage.PasswordS.Clear();
}
[When(@"I view the Login Page")]
public void WhenIViewTheLoginPage()
{
Thread.Sleep(2000);
Assert.AreEqual(Driver.Url, "http://qa-URL-Ommitted");
}
[When(@"I enter invalid Username of ""(.*)""")]
public void WhenIEnterInvalidUsernameOf(string invalidUsername)
{
var signinpage = new SignInPage(Driver);
Thread.Sleep(10);
signinpage.UserNameS.Clear();
signinpage.UserNameS.SendKeys(invalidUsername);
}
[When(@"enter an invalid Password ""(.*)""")]
public void WhenEnterAnInvalidPassword(string invalidPassword)
{
var signinpage = new SignInPage(Driver);
Thread.Sleep(10);
signinpage.PasswordS.Clear();
signinpage.PasswordS.SendKeys(invalidPassword);
}
[When(@"the submit button is pressed")]
public void WhenTheSubmitButtonIsPressed()
{
var signinpage = new SignInPage(Driver);
signinpage.SubmitButtonS.Click();
}
[Then(@"everything I need to login is present")]
public void ThenEverythingINeedToLoginIsPresent()
{
var UserActions = new UserActions(Driver);
var signinpage = new SignInPage(Driver);
UserActions.WaitForElement(Driver, signinpage.TimeServicesSignInTitle);
UserActions.WaitForElement(Driver, signinpage.UserNameText);
UserActions.WaitForElement(Driver, signinpage.PasswordText);
UserActions.WaitForElement(Driver, signinpage.RememberMeText);
}
[Then(@"the browser is closed")]
public void ThenTheBrowserIsClosed()
{
Driver.Dispose();
}
[Then(@"an Invalid Name or Password error will display on a popup")]
public void ThenAnInvalidNameOrPasswordErrorWillDisplayOnAPopup()
{
var signinpage = new SignInPage(Driver);
bool InvalidPopUp = signinpage.InvalidPasswordAndOrUserNameS.Displayed;
}
[Then(@"an error message will display under the username field of ""(.*)""")]
public void ThenAnErrorMessageWillDisplayUnderTheUsernameFieldOf(string usernameError)
{
var signinpage = new SignInPage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, signinpage.UserNameRequired);
Assert.AreEqual(usernameError, signinpage.UserNameRequiredS.Text);
}
[Then(@"an error message will display under the password field of ""(.*)""")]
public void ThenAnErrorMessageWillDisplayUnderThePasswordFieldOf(string passwordError)
{
var signinpage = new SignInPage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, signinpage.PasswordRequired);
Assert.AreEqual(passwordError, signinpage.PasswordRequiredS.Text);
}
}
}
FeatureFile 2:ServiceSchedule功能
@All @ServiceSchedules
Feature: ServiceSchedules
In order to use the Program
As a User
I want to be be able to easily Search, Create and Edit ServiceSchedules upon login, from the homepage
Background:
Given I have logged on
@Content
Scenario: ServiceScheduleLoginPageContent
When I view the Homepage Page
Then I am taken to the Dashboard ServiceSchedules homepage
And the correct breadcrumb of "Dashboard" and "Serivce Schedules" are present
And the Customer Details search options appear
And the Export and Search buttons appear
And the results pane appears
And the results pane has a quick filter
And the browser is closed
ServiceScheduleSteps.cs
using NUnit.Framework;
using OpenQA.Selenium;
using System;
using System.Threading;
using TechTalk.SpecFlow;
using Selenium.Services.SpecFlow2.Pages;
namespace Selenium.Services.SpecFlow2
{
[Binding]
public class ServiceSchedulesSteps
{
public IWebDriver Driver { get; private set; }
[When(@"I view the Homepage Page")]
public void WhenIViewTheHomepagePage()
{
Thread.Sleep(2000);
Assert.AreEqual(Driver.Url, "http://qa-URL-Omitted");
}
[Given(@"I have logged on")]
public void GivenIHaveLoggedOn()
{
Driver = UserActions.IntializeDriver();
SignInPage signinpage = new SignInPage(Driver);
UserActions.FillLogInField(Config.Credentials.Valid.Username, Config.Credentials.Valid.Password, Driver);
signinpage.SubmitButtonS.Click();
Thread.Sleep(1000);
}
[Then(@"I am taken to the Dashboard ServiceSchedules homepage")]
public void ThenIAmTakenToTheDashboardServiceSchedulesHomepage()
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, homePage.BreadCrumbServiceSchedules);
}
[Then(@"the top navigation is present")]
public void ThenTheTopNavigationIsPresent()
{
var menu = new Menu(Driver);
bool MenuAdmin = menu.Admin.Displayed;
bool MenuWorkShop = menu.WorkShops.Displayed;
bool MenuParts = menu.JobTemplate.Displayed;
bool MenuSearch = menu.Search.Displayed;
}
[Then(@"the correct breadcrumb of ""(.*)"" and ""(.*)"" are present")]
public void ThenTheCorrectBreadcrumbOfAndArePresent(string breadcrumb1, string breadcrumb2)
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, homePage.BreadCrumbDashboard);
Assert.AreEqual(breadcrumb1, homePage.BreadCrumbDashboardS.Text);
UserActions.WaitForElement(Driver, homePage.BreadCrumbServiceSchedules);
Assert.AreEqual(breadcrumb2, homePage.BreadCrumbServiceSchedulesS.Text);
}
[Then(@"the Customer Details search options appear")]
public void ThenTheCustomerDetailsSearchOptionsAppear()
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
//Pane Expand Button
UserActions.WaitForElement(Driver, homePage.FilterSchedulesExpandButton);
UserActions.WaitForElement(Driver, homePage.CustomerNameField);
UserActions.WaitForElement(Driver, homePage.CustomerEmailField);
UserActions.WaitForElement(Driver, homePage.CustomerPhoneField);
UserActions.WaitForElement(Driver, homePage.CustomerPostcodeField);
}
[Then(@"the Export and Search buttons appear")]
public void ThenTheExportAndSearchButtonsAppear()
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, homePage.ExportButton);
UserActions.WaitForElement(Driver, homePage.SearchButton);
}
[Then(@"the results pane appears")]
public void ThenTheResultsPaneAppears()
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, homePage.CustomerResultsTable);
UserActions.WaitForElement(Driver, homePage.RTableCustomerNo);
UserActions.WaitForElement(Driver, homePage.RTableCustomer);
UserActions.WaitForElement(Driver, homePage.RTableWatch);
UserActions.WaitForElement(Driver, homePage.RTableTotalCosts);
UserActions.WaitForElement(Driver, homePage.RTableDates);
UserActions.WaitForElement(Driver, homePage.RTableActions);
UserActions.WaitForElement(Driver, homePage.Pagination);
}
[Then(@"the results pane has a quick filter")]
public void ThenTheResultsPaneHasAQuickFilter()
{
var homePage = new HomePage(Driver);
var UserActions = new UserActions(Driver);
UserActions.WaitForElement(Driver, homePage.QuickFilter);
}
}
}
希望我有足够的机会继续工作-一切正常,只是无法理解为什么LoginPageSteps.cs中的“和浏览器已关闭”步骤不会与ServiceSchedules.feature中的方案/测试共享自身文件。我认为这可能与方法有关,并且我首先在哪里初始化驱动程序?不知道我该怎么做。.
我确实发现我能够在ServiceSchedules.feature和ServiceSchedulesSteps.cs文件中创建一个新步骤“并且浏览器关闭”,并且工作正常,但这当然意味着我有两个相同的步骤,并且实际上应该从一个地方共享一个文件-这就是我认为所有工作都应该如此的方式!
非常感谢您对此提供的任何帮助-我对此深表歉意,这是我已经错过或没有理解的明显而愚蠢的东西-我正在学习并且对编码还比较陌生:)
欢呼
答案 0 :(得分:0)
您遇到的关键时刻是线程从And the browser is closed
场景开始执行ServiceScheduleLoginPageContent
的情况。在这种情况下,线程将进入step方法(其定义位于LoginPageSteps
类中),并且在您尝试调用Driver.Dispose();
时会出现错误。这是因为您使用了未初始化的DRIVER变量。由于您的执行过程始于ServiceSchedulesSteps
类,因此它永远不会初始化。您已经在class ServiceSchedulesSteps
中初始化了Driver变量。
我想说,[AfterScenario]可能是导致统一变量的原因。
发生这种情况是因为您的步骤And the browser is closed
在2个不同的.feature文件中具有相同的语法。当您在不同的.feature文件中具有相同的步骤时,specFlow将识别出在您的项目内部已经为您的步骤定义了步骤方法(这是因为您为步骤类设置了[Binding]属性)。
每个人都建议您阅读有关规范流程的上下文注入主题。它允许在不同的step.cs文件之间共享数据。但是,如果随着更多场景或功能的增加,用于共享的参数不断增加,则应考虑如何处理。您只要在Google上搜索它,就会在文档或某些博客中找到它。
您还可以坚持简单的解决方案,重命名And the browser is closed
步骤之一并让其生成新方法,这样您就有了2个步骤方法,将一个功能文件中的所有步骤保留在一个step.cs文件中,并避免使用这些方法有点问题。现在,请考虑您的方案/功能可能会如何变化,但不要太在意您会随着时间的推移而处理它。但是上下文注入绝对值得尝试。