【问题标题】:What is the best practice for handling Try Catch when writing automated testing?编写自动化测试时处理 Try Catch 的最佳实践是什么?
【发布时间】:2016-08-12 10:47:15
【问题描述】:

我目前正在为我的公司编写基于 Web 的应用程序的测试自动化。我正在使用 C#、Visual Studio 测试套件和 Selenium 来执行测试。

今天我向我的同事提出了一个问题,即“代码中是否存在过多的 Try Catch 块?”。他的回答是不能像我现在那样工作(参见示例 1),而是让较低级别的 try-catch 抛出到较高级别的 try-catch 以便可以在那里写入异常并且测试失败(见示例 2)。

示例 1:

TestCase.cs

[TestMethod]
public void TestLogin()
{
    Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
    Console.WriteLine(@"Login Successful");    
}

FW_Shared.cs

public static class FW_Shared
{
    public static string OrgCode = "Test123";
    public static string Username = "Tester";
    public static string Password = "Password";

    public static void Perform_Login(string OrgCode, string Username, string Password)
    {
        try
        {
            Driver.Url = "http://test.app.com/";
            Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
            Driver.FindElement(By.Id("username")).SendKeys(Username);
            Driver.FindElement(By.Id("password")).SendKeys(Password);
            Driver.FindElemenet(By.Id("btnsubmit)).Click();
        }
        catch (Exception ex)
        {
             Console.WriteLine(@"Error occurred logging on: " + ex.ToString());
             return false;
        }
        return true;
    }
}

示例 2

TestCase.cs

[TestMethod]
public void TestLogin()
{
    try
    {
        Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
        Console.WriteLine(@"Login Successful");  
    }
    catch (Exception ex)
    {
        Console.WriteLine(@"Exception caught, test failed: " + ex.ToString());
        Assert.Fail();
    }  
}

FW_Shared.cs

public static class FW_Shared
{
    public static string OrgCode = "Test123";
    public static string Username = "Tester";
    public static string Password = "Password";

    public static void Perform_Login(string OrgCode, string Username, string Password)
    {
        try
        {
            Driver.Url = "http://test.app.com/";
            Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
            Driver.FindElement(By.Id("username")).SendKeys(Username);
            Driver.FindElement(By.Id("password")).SendKeys(Password);
            Driver.FindElemenet(By.Id("btnsubmit)).Click();
        }
        catch (Exception)
        {
             throw;
        }
        return true;
    }
}

现在我知道抛出要捕获的异常在典型编码中通常是无用的,因为您想要处理返回的特定异常,但我希望能够捕获任何一般网页或元素问题,以便测试失败关于 Web 应用程序的一般问题。例如:

  • 如果网页返回 503 或 404 问题
  • 如果当前网页上不存在某个元素
  • 如果元素名称已更改。

在测试应用程序的其他更复杂的部分时,我使用 true/false bool 返回处理无法访问的部分/元素并断言这一点,但由于我在不同的类中引用多个函数,所以会坚持我所拥有的最好,转移到所有较低异常的顶级捕获,还是我应该做其他事情?

【问题讨论】:

  • 最好的做法是不使用try/catch。捕获异常将使追查问题的根源变得更加困难。如果您想要自定义消息,请使用适当的断言方法,如果您想确切知道哪个功能失败,请为测试方法使用显式名称:ShouldLoginSuccessfully
  • 我们对特定部分进行了验证,例如我们期望 Selenium 在哪个页面上,等等。我只是想知道一般异常捕获的最佳方法以及如何处理失败的测试.

标签: c# selenium testing automated-tests


【解决方案1】:

我通常喜欢在它自己的名为“TestRunner.cs”的类中创建一个测试助手方法,它有一个方法用于所有可能引发异常的测试,我想测试例如结果

public static Exception RunCodeThatMayThrowException(Action action)
{
    try
    {
        action.Invoke();
        return null;
    }
    catch (Exception ex)
    {
        return ex;
    }
}

然后我可以使用如下方法:

// Act
var actualException = TestRunner.RunCodeThatMayThrowExeption(() => {//some code});

// Assert
//Do some asserts

【讨论】:

  • 那么你会使用你的测试助手来调用一个动作,比如去一个特定的 URL 或者尝试设置一个新的对象实例吗?如果是这样,您是否必须检查“var actualException”是否为空?
  • 在您实际期望抛出异常的情况下。在这种情况下,您可以使用方法“RunCodeThatMayThrowException”作为一种简单的方法来证明异常已被抛出,是正确的异常类型并包含您想要的消息。我倾向于让异常通过层冒泡而不捕获它们,除非它位于全局位置,例如错误事件处理程序上的 global.asax
【解决方案2】:

您原来的 Perform_Login 方法声明没有返回参数 ('void') 并且始终返回 'true'(除非发生崩溃)——这些都暗示该方法需要一些重构。

我将重构如下,它将调用代码与异常隔离,使调用者不知道被调用方法中的任何错误,并避免一系列 try-catch 传递调用堆栈(如果您的测试有一个 try-catch 然后调用该方法的生产代码很可能需要相同的):

Public Static Class FW_Shared
{
    public static string OrgCode = "Test123";
    public static string Username = "Tester";
    public static string Password = "Password";

    public static bool Perform_Login(string OrgCode, string Username, string Password)
    {
        Try
        {
            Driver.Url = "http://test.app.com/";
            Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
            Driver.FindElement(By.Id("username")).SendKeys(Username);
            Driver.FindElement(By.Id("password")).SendKeys(Password);
            Driver.FindElemenet(By.Id("btnsubmit)).Click();
        }
        Catch (Exception ex)
        {
             Console.WriteLine(@"Error occurred logging on: " + ex.ToString());
             return false;
        }
        return true;
    }
}

[TestMethod]
Public Void TestLoginSuccess()
{
    Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
    Console.WriteLine(@"Login Successful");    
}


[TestMethod]
Public Void TestLoginFailure()
{
    Assert.IsFalse(FW_Shared.Perform_Login(FW_Shared.OrgCode, “foo”, “bar”));
    Console.WriteLine(@"Login Failed");    
}

【讨论】:

  • 给出的例子就是这样,一个例子。实际登录性能将用于初始化每个测试,因为在执行操作(例如将文档添加到我们的 Web 应用程序)之前,硒需要在相关页面上。我们有一个数据驱动的测试,它会遍历每个登录并验证这些。我需要了解 TryCatch 的最佳实践以及如何采取行动,但我很感激您的回答。
  • 没有问题 - 不确定它是否有帮助,您可能已经意识到这一点,但您可以将测试设置为预期特定类型的异常。这确实因框架而异,但 MSTest 或 Nunit 有(或至少有)一个方法注释,例如,'[ExpectedException(typeOf(NotImplementedException))]'。这在您的场景中可能有用也可能没有用(对不起,我现在已经更正了之前的“你是” :-))。
  • 如果可以捕获未实现的异常,这可能是我需要解决的问题。我会看看这个,谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-03-26
  • 2021-10-02
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多