测量自动化测试步骤执行时间

时间:2016-07-09 00:28:48

标签: c# automation automated-tests reporting coded-ui-tests

我有10种测试方法,每种方法都有一些自动化的业务功能,例如Login(), CreateSomeRecord(), EditSomeRecord(), DeleteSomeRecord(), etc.

我还有一个HTML报告,它将捕获在测试方法中完成的操作(基本上捕获测试步骤)。像这样:

1. Enter Username: user01   User Entered Successfully   Pass
2. Enter Password: pass01   Pass Entered Successfully   Pass
3. Click Login button       Login successful            Pass

我基本上是逐行从代码构造HTML文件。 现在,我想再添加一列来捕获持续时间 - 完成特定步骤所需的时间。

所以,我正在做这样的事情:

// Initializing a new instance of the Stopwatch class
Stopwatch stopWatch = new Stopwatch();
TimeSpan ts;
string elapsedTime;

//Username field
stopWatch.Start();
WpfEdit usrName = new WpfEdit(wpfWndObj);
#region Search Criteria
usrName.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "Usertxt";
usrName.WindowTitles.Add("My Test Application");
#endregion
Keyboard.SendKeys(usrName, usn); //usn has my username value in it
stopWatch.Stop();
ts = stopWatch.Elapsed;
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
//Writing a new row into my HTML report
RptRowValueAdd(ReportDt, "", "Enter Username: " + usn, "Username Entered Successfully", "Pass", "", elapsedTime);
stopWatch.Reset();

RptRowValueAdd函数的内容

//DataTable tblObj is a dataset.
//I am writing the report into data-set first before writing it into a HTML file
public void RptRowValueAdd(DataTable tblObj, String TcName, String StepName, String ActRes, String Status, String ScrShtName, String TotalTimer = "", String BeginTimer = "", String EndTimer = "", String TestMethodName = "")
{
    tblObj.NewRow();
    tblObj.Rows.Add(ReportRowValue, TcName, StepName, ActRes, Status, ScrShtName,TotalTimer);
    ReportRowValue = ReportRowValue + 1;
}

这实际上有效,但想象一下编写启动秒表,停止它,计算经过的时间然后重置它所涉及的时间。我需要为我写入HTML报告文件的每一行执行此操作。

当我想到为所有10种测试方法做这种方式时,它开始变得很麻烦。

有没有更好的方法对此进行编码?

我不是在寻找任何基于探测器(ANTS)的解决方案。我知道分析人员是出于那个目的,但我想知道是否有更好的方法来处理我目前正在从代码中做的事情。

感谢您的指导。

2 个答案:

答案 0 :(得分:1)

我想我错过了一些细节,例如RptRowValueAdd中发生了什么 - 你怎么知道用户名输入成功并且测试通过了?无论如何,也许这种方法会给你一些想法。

有一个代表每个测试数据的类:

public class TestDetails
{
    public string TestName { get; set; }
    public string ResultDescription { get; set; }
    public Result TestResult { get; set; }
    public string ElapsedTime { get; set; }

    public TestDetails(string testName, string resultDescription, Result result, string elapsedTime)
    {
        ResultDescription = resultDescription;
        TestResult = result;
        ElapsedTime = elapsedTime;
    }

    public enum Result
    {
        Pass,
        Fail
        // etc
    }
}

然后,创建一个方法,将测试作为操作参数并返回测试的详细信息。

    public static TestDetails RunTest(Action testMethod)
    {
        var sw = new Stopwatch();
        TimeSpan ts;
        string elapsedTime;
        sw.Start();
        testMethod.Invoke();
        sw.Stop();
        ts = sw.Elapsed;
        elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);

        return new TestDetails("Enter username: ", "Username entered Successfully", TestDetails.Result.Pass, elapsedTime);
    }

要使用这些,您可以创建一个操作方法列表,您可以在其中添加所有测试并在foreach中调用它们:

        var tests = new List<Action>
        (
            Login,
            CreateSomeRecord,
            EditSomeRecord,
            DeleteSomeRecord
        );

        foreach (var test in tests)
        {
            var testDetails = RunTest(test);
            RptRowValueAdd(ReportDt, "", testDetails.TestName, testDetails.ResultDescription, testDetails.TestResult.ToString(), testDetails.ElapsedTime);
        }

我希望我没有误会你。

由于

答案 1 :(得分:1)

First, as I have pointed out in a few of your questions, I would not drive my tests like you have illustrated. You are requiring test methods to execute in some particular order. Further, you are requiring that the assertions be run in every case, even after they have been verified working. For example, all your assertions in the Enter User Name method will run on every orchestration that involves setting the user name. This kind of defeats the point of testing the login by itself. After the tests for setting the user name have passed, all other tests can just assume that it works. Depending on the assertions, it can increase the time dramatically to perform them every time.

That said, I would create something separate that can orchestrate your tests. This orchestration class can have timings associated with each step. However, it is unclear how you are using the timings (if at all).

My blog covers this, but to hightlight what it could look like:

// orchestrates login user action
interface ILoginActions
{
    // logs in the user and returns a reference to the account settings page
    // which appears after successful login
    IAccountSettings Login(string username, string password);
}

public class LoginActions : ILoginActions
{
    public readonly ILoginPage loginPage;
    public LoginActions(ILoginPage loginPage)
    {
        this.loginPage = loginPage;
    }

    public IAccountSettings Login(string username, string password)
    {
        // the orchestrator does not typically need to make assertions,
        // and can assume that there are tests for Login actions
        stopWatch.Start();

        var model = 
        this.loginPage
            .Username.SetValue(username)
            .Password.SetValue(password)
            .Login.Click();

        stopWatch.Stop();

        log("Login Timing", stopWatch.Elapsed);

        return model;
    }
}

To reiterate, the above orchestration class exists on the presumption that there is a full set of tests for the login page that do not use the orchestration class.

The timings in the test methods them selves would have to be done either as you have already identified, or maybe some hybrid with @Mvarta's answer.