C# Specflow - BeforeScenario 挂钩未被调用且驱动程序为空
C# Specflow - BeforeScenario hook is not being called and driver gets null
我对 Specflow 和 C# 还很陌生,所以我遇到了 specflow 挂钩问题。
问题是:当我使用 [BeforeScenario] 时,调试时甚至没有调用该方法。
删除这些挂钩并将其替换为 [TestInitialize],它可以完美运行。
我在这里搜索了很多问题的解决方案,但是除了私有方法之外我没有发现任何问题,这似乎不是我的情况。
我有 4 个 classes:测试、步骤、PageObjects 和挂钩(包含驱动程序和挂钩)。
'Tests' class继承自'Steps',后者继承自'PageObjects',后者继承自'Hooks'。
每次调用都是 public,我正在写下来自 'Hooks' class:
的一些代码
namespace AutomationPractice.Helper
{
[Binding]
public class Hooks
{
public IWebDriver _driver;
[BeforeFeature]
public void BeforeScenario()
{
if (_driver == null)
{
_driver = new ChromeDriver();
}
else { throw new Exception("Couldn't initialize the driver"); }
}
[AfterFeature]
public void AfterScenario()
{
if (_driver != null)
{
_driver.Quit();
}
else throw new Exception("There was an error while trying to close the driver");
}
}
}
'PageObjects' class:
namespace AutomationPractice.PageObjects
{
[Binding]
public class GoogleSearchPageObjects : Hooks
{
public string goToGooglePage(string url)
{
return _driver.Url = url;
}
public IWebElement GetTxtSearch()
{
return _driver.FindElement(By.Name("q"));
}
public void fillTxtSearch(string search)
{
GetTxtSearch().SendKeys(search);
}
}
}
'Steps' class:
namespace AutomationPractice.Steps
{
[Binding]
public class GoogleSearchSteps : GoogleSearchPageObjects
{
[Given(@"I am on google home page")]
public void GivenIAmOnGoogleHomePage(string url)
{
goToGooglePage(url);
}
[When(@"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
fillTxtSearch(search);
}
虽然每个 class 都被 [绑定] 四舍五入。
提前致谢!
您的方法名称为 BeforeScenario
和 AfterScenario
,但您使用的是 BeforeFeature
和 AfterFeature
的属性。
这些必须是静态的才能被调用。
您需要更改属性。
您在同一 class 层次结构中进行的事情太多。解耦以下内容会简单得多:
- Web 驱动程序
- 页面对象
- 步骤定义
您可以使用 SpecFlow 的依赖注入框架使用构造函数参数将这些东西连接在一起。
首先是你的 Hooks class,你可以在其中管理所有步骤定义和页面对象的 Web 驱动程序实例:
[Binding]
public class Hooks
{
private IObjectContainer container;
public Hooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
var driver = new ChromeDriver();
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
driver.Quit();
driver.Dispose();
}
}
并且 google 搜索页面对象成为一个单独的 class,它接收 Web 驱动程序对象作为构造函数参数,从而将其与 SpecFlow 完全分离。
public class GoogleSearchPage
{
private readonly IWebDriver driver;
private IWebElement TxtSearch => driver.FindElement(By.Name("q"));
public GoogleSearchPage(IWebDriver driver)
{
this.driver = driver;
}
public void EnterSearchTerm(string searchTerm)
{
TxtSearch.SendKeys(searchTerm);
}
}
最后是步骤定义 class,这是通过 SpecFlow 附带的依赖注入框架将所有内容连接在一起的地方:
[Binding]
public class GoogleSearchSteps
{
private GoogleSearchPage googleSearch;
public GoogleSearchSteps(IWebDriver driver)
{
googleSearch = new GoogleSearchPage(driver);
}
[When(@"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
googleSearch.EnterSearchTerm(search);
}
}
您现在遇到的部分问题是 class 层次结构。您正在混合 class 应该分开但要协调的元素。通过将步骤定义与 Web 驱动程序的初始化分开,并将页面对象保留在它自己的 class 中,您可以组织这些对象之间的依赖关系并将其限制在它们所需要的范围内(解耦),但仍然允许它们一起工作(凝聚力)。
我对 Specflow 和 C# 还很陌生,所以我遇到了 specflow 挂钩问题。 问题是:当我使用 [BeforeScenario] 时,调试时甚至没有调用该方法。 删除这些挂钩并将其替换为 [TestInitialize],它可以完美运行。 我在这里搜索了很多问题的解决方案,但是除了私有方法之外我没有发现任何问题,这似乎不是我的情况。
我有 4 个 classes:测试、步骤、PageObjects 和挂钩(包含驱动程序和挂钩)。 'Tests' class继承自'Steps',后者继承自'PageObjects',后者继承自'Hooks'。 每次调用都是 public,我正在写下来自 'Hooks' class:
的一些代码 namespace AutomationPractice.Helper
{
[Binding]
public class Hooks
{
public IWebDriver _driver;
[BeforeFeature]
public void BeforeScenario()
{
if (_driver == null)
{
_driver = new ChromeDriver();
}
else { throw new Exception("Couldn't initialize the driver"); }
}
[AfterFeature]
public void AfterScenario()
{
if (_driver != null)
{
_driver.Quit();
}
else throw new Exception("There was an error while trying to close the driver");
}
}
}
'PageObjects' class:
namespace AutomationPractice.PageObjects
{
[Binding]
public class GoogleSearchPageObjects : Hooks
{
public string goToGooglePage(string url)
{
return _driver.Url = url;
}
public IWebElement GetTxtSearch()
{
return _driver.FindElement(By.Name("q"));
}
public void fillTxtSearch(string search)
{
GetTxtSearch().SendKeys(search);
}
}
}
'Steps' class:
namespace AutomationPractice.Steps
{
[Binding]
public class GoogleSearchSteps : GoogleSearchPageObjects
{
[Given(@"I am on google home page")]
public void GivenIAmOnGoogleHomePage(string url)
{
goToGooglePage(url);
}
[When(@"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
fillTxtSearch(search);
}
虽然每个 class 都被 [绑定] 四舍五入。
提前致谢!
您的方法名称为 BeforeScenario
和 AfterScenario
,但您使用的是 BeforeFeature
和 AfterFeature
的属性。
这些必须是静态的才能被调用。
您需要更改属性。
您在同一 class 层次结构中进行的事情太多。解耦以下内容会简单得多:
- Web 驱动程序
- 页面对象
- 步骤定义
您可以使用 SpecFlow 的依赖注入框架使用构造函数参数将这些东西连接在一起。
首先是你的 Hooks class,你可以在其中管理所有步骤定义和页面对象的 Web 驱动程序实例:
[Binding]
public class Hooks
{
private IObjectContainer container;
public Hooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
var driver = new ChromeDriver();
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
driver.Quit();
driver.Dispose();
}
}
并且 google 搜索页面对象成为一个单独的 class,它接收 Web 驱动程序对象作为构造函数参数,从而将其与 SpecFlow 完全分离。
public class GoogleSearchPage
{
private readonly IWebDriver driver;
private IWebElement TxtSearch => driver.FindElement(By.Name("q"));
public GoogleSearchPage(IWebDriver driver)
{
this.driver = driver;
}
public void EnterSearchTerm(string searchTerm)
{
TxtSearch.SendKeys(searchTerm);
}
}
最后是步骤定义 class,这是通过 SpecFlow 附带的依赖注入框架将所有内容连接在一起的地方:
[Binding]
public class GoogleSearchSteps
{
private GoogleSearchPage googleSearch;
public GoogleSearchSteps(IWebDriver driver)
{
googleSearch = new GoogleSearchPage(driver);
}
[When(@"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
googleSearch.EnterSearchTerm(search);
}
}
您现在遇到的部分问题是 class 层次结构。您正在混合 class 应该分开但要协调的元素。通过将步骤定义与 Web 驱动程序的初始化分开,并将页面对象保留在它自己的 class 中,您可以组织这些对象之间的依赖关系并将其限制在它们所需要的范围内(解耦),但仍然允许它们一起工作(凝聚力)。