C# 在编写自动化测试时,处理Try-Catch的最佳实践是什么?

C# 在编写自动化测试时,处理Try-Catch的最佳实践是什么?,c#,selenium,testing,automated-tests,C#,Selenium,Testing,Automated Tests,我目前正在为我的公司编写一个基于web的应用程序的测试自动化。我正在使用C#、Visual Studio测试套件和Selenium来执行测试 今天,我向我的同事提出了一个问题:“是否有任何时候代码中有太多的Try-Catch块?”。他的回答是没有像我现在这样工作(参见示例1),而是让较低级别的try-catch抛出到较高级别的try-catch,这样就可以在那里编写异常,并且测试失败(参见示例2) 例1: TestCase.cs [TestMethod] public void TestLogi

我目前正在为我的公司编写一个基于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");    
}
[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 ex)
        {
             Console.WriteLine(@"Error occurred logging on: " + ex.ToString());
             return false;
        }
        return true;
    }
}
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;
    }
}
例2

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");    
}
[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 ex)
        {
             Console.WriteLine(@"Error occurred logging on: " + ex.ToString());
             return false;
        }
        return true;
    }
}
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返回来处理不可访问的部分/元素,并断言这一点,但由于我在不同的类中引用多个函数,因此我会坚持我最好的方法,转而从顶层捕获所有较低的异常,或者我应该做些别的事情吗?

我通常喜欢在自己的类“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

我通常喜欢在自己的类“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

原始的Perform\u Login方法没有返回参数('void'),并且总是返回'true'(除非发生崩溃)–这两种方法都暗示该方法需要重新分解

我将按如下方式重新考虑,这将调用代码与异常隔离,使调用方对被调用方法中的任何错误不可知,并避免了一系列传递调用堆栈的try-catch(如果测试中有try-catch,则调用该方法的生产代码可能需要相同的try-catch):


原始的Perform\u Login方法没有返回参数('void'),并且总是返回'true'(除非发生崩溃)–这两种方法都暗示该方法需要重新分解

我将按如下方式重新考虑,这将调用代码与异常隔离,使调用方对被调用方法中的任何错误不可知,并避免了一系列传递调用堆栈的try-catch(如果测试中有try-catch,则调用该方法的生产代码可能需要相同的try-catch):


最好的做法是不要使用
try/catch
。捕获异常将使追踪问题根源变得更加困难。如果您想要自定义消息,则使用适当的assert方法,如果您想要确切知道哪个功能失败,则为测试方法使用显式名称:
shouldloginssuccessfully
。我们对特定部分进行了验证,例如希望Selenium出现在哪个页面上,等等。我只是想知道一般异常捕获的最佳方法,以及如何在测试失败的情况下处理它。最好的做法是不要使用
try/catch
。捕获异常将使追踪问题根源变得更加困难。如果您想要自定义消息,则使用适当的assert方法,如果您想要确切知道哪个功能失败,则为测试方法使用显式名称:
shouldloginssuccessfully
。我们对特定部分进行了验证,例如希望Selenium出现在哪个页面上,等等。我只是想知道一般异常捕获的最佳方法,以及如何在测试失败的情况下处理它。给出的示例就是这样一个示例。实际登录性能将用于初始化每个测试,因为selenium需要在执行操作(如向web应用程序添加文档)之前出现在相关页面上。我们有一个数据驱动的测试,通过每个登录并验证这些。我需要知道TryCatch的最佳实践以及如何操作,但我很感激答案。没有问题-不确定它是否有用,您可能已经意识到这一点,但您可以将测试设置为预期特定类型的异常。这在不同的框架中有所不同,但MSTest或Nunit都有(或至少有)类似于[ExpectedException(typeOf(NotImplementedException))]的方法注释。这在您的场景中可能有用,也可能不有用(很抱歉前面的“you's”,我现在已经更正了:-)。如果这可以捕获未实现的异常,那可能就是我需要解决的问题。我来看看这个,谢谢。举的例子就是那个,一个例子。实际登录性能将用于初始化每个测试,因为selenium需要在执行操作(如向web应用程序添加文档)之前出现在相关页面上。我们有一个数据驱动的测试,通过每个登录并验证这些。我需要知道TryCatch的最佳实践以及如何操作,但我很感激答案。没有问题-不确定它是否有用,您可能已经意识到这一点,但您可以将测试设置为预期特定类型的异常。这确实因框架而异,但MSTest或Nunit都有(或至少有)一个类似于“[Expect]的方法注释