/// <summary>
/// clicks on an element given the elements ID and a waiting timeout
/// </summary>
/// <param name="driver"></param>
/// <param name="ID"></param>
/// <param name="timeout"></param>
public static void clickElement(IWebDriver driver, String ID, int timeout)
{
try
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
wait.Until(ExpectedConditions.ElementToBeClickable(By.Id(ID)));
driver.FindElement(By.Id(ID)).Click();
}
catch (NoSuchElementException)
{
MessageBox.Show("On Selenium Action click " + ID + " after 10 seconds, this button didn't appear on the page", "Use Case 1 Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
}
catch (TimeoutException)
{
MessageBox.Show("After waiting for 10 seconds, the page was not loaded !", "Use case Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
我试图让这个函数区分我要捕获的两种类型的异常,其中没有加载页面或按钮不存在(ID已被更改或按钮已被删除)。< / p>
答案 0 :(得分:1)
TimeoutException可以指示单击操作未正确返回 - 这被视为驱动程序超时。例如:您单击提交按钮,服务器正在处理请求5分钟,但驱动程序超时为60秒 - 因此超时。
您似乎正在使用静态方法的约定,很可能是在函数库中。 我会劝阻这种方法 - 因为它是面向对象的反模式。
在我们自己的测试框架中,我们有专门的类型来封装Selenium提供的IWebElement类/接口,并且我们将自己的功能置于其上。
所以不要打电话
IWebElement textbox = Driver.FindElement(By.Id("username"));
textbox.TypeKeys("Administrator");
我们致电
Textbox mytextbox = new Textbox(By.Id("username"));
mytextbox.SetText("Administrator");
如果需要,Textbox类的构造函数将执行存在性检查(或不存在检查)。
此外 - 我们有另一个名为'IPage / Page'的专用接口/类 它实现了IDisposable,因此我们可以在Using()语句的上下文中使用Page Object模型。
例如:
using(LoginPage page = new LoginPage())
{
page.UsernameTextBox().SetText("Administrator");
page.PasswordTextBox().SetText("Password12121212");
page.SubmitButton().Click();
}
通过将IDisposable与您的页面模型方法结合使用,您可以使其成为LoginPage类的构造函数 - 知道在登录页面本身上的特定对象上进行同步。 例如: 当LoginPage类被实例化时,我们检查UsernameTextBox是否存在 - 如果它不存在,那么页面没有正确加载,因此,执行using语句的内容是没有意义的。
我通常建议将同步对象设置为每页预期加载到屏幕上的最后一个对象。 这样,您可以让代码智能地等待页面加载,然后再继续进入using语句的内部上下文。
使用此方法,您可以检测页面是否加载失败,或者对象是否加载失败。 让我们不要忘记,页面可以加载,但仍然是通过测试中的应用程序的数据或代码问题的错误页面。 这是TimeoutException无法捕获的场景。
我们在框架中遵循的典型结构是 - 以防您想要建模类似的东西。
BaseElement - 将IWebElement作为私有字段 - 所有工作都在IWebElement上完成。 BaseElement将在此级别定义和实现大多数功能,作为受保护或公共方法。
然后我们在定义其他专用类时从BaseElement扩展/继承。 例如:ButtonLink,Textbox,DropdownSelects,RadioCheckboxes等
我们在适当的地方覆盖方法,或者简单地将调用重定向到BaseElement中的基本方法。
我们以这种方式设计框架的理由是基于“不是每个文件都是文本框的逻辑,所以为什么你会这样对待它?” 在这种情况下 - 如果有问题的对象实际上是下拉列表,我们只获得下拉的intellisense / options。
在.Net编码/编程中 - 强烈打字你的课程通常是一个鼓励的原则 - 所以像所有其他类型的课程一样处理 - 即使Selenium或更广泛的QA社区允许/鼓励它,也不一定是个好主意。 在基础Selenium类型之上构建框架将允许您处理需要使用Javascript单击按钮的定制场合,或者您需要从Highchart图表等中获取数据
对不起咆哮 - 我只是觉得这可能是值得思考的问题,也是解决问题的另一种方法。