C# 使用Selenium和NUnit测试执行顺序的UI自动化测试

C# 使用Selenium和NUnit测试执行顺序的UI自动化测试,c#,selenium-webdriver,automated-tests,nunit,qa,C#,Selenium Webdriver,Automated Tests,Nunit,Qa,这几乎是我自动化测试的开始,所以如果我不能向您解释清楚,我想向您道歉 因此,在阅读了两周有关自动化的博客后,我决定将NUNIT与Selenium Webdriver一起用于UI自动化 我的应用程序是企业级的,已经重新开发了3年。它是一个项目和投资组合管理系统 我有数百个页面,其中大约50%执行CRUD操作 我为我的申请决定了以下结构: 我使用以下格式的测试数据作为JSON,并将这些数据重新保存到我的视图模型中: [ { "Name": "Finance", "Descrip

这几乎是我自动化测试的开始,所以如果我不能向您解释清楚,我想向您道歉

因此,在阅读了两周有关自动化的博客后,我决定将NUNITSelenium Webdriver一起用于UI自动化

我的应用程序是企业级的,已经重新开发了3年。它是一个项目和投资组合管理系统

我有数百个页面,其中大约50%执行CRUD操作

我为我的申请决定了以下结构:

我使用以下格式的测试数据作为JSON,并将这些数据重新保存到我的视图模型中:

[
  {
    "Name": "Finance",
    "Description": "division with complete test data",
    "Color": "#ff0000",
    "ExpectedStatus": {
      "WillBeAdded": true,
      "WillBeDeleted": true,
      "WillBeUpdated": true
    },
    "PerformableActions": {
      "ShouldAdd": true,
      "ShouldDelete": false,
      "ShouldUpdate": true
    }
  },
  {
    "Name": "IT",
    "Description": "IT projects",
    "Color": "pink",
    "ExpectedStatus": {
      "WillBeAdded": true,
      "WillBeDeleted": true,
      "WillBeUpdated": true
    },
    "PerformableActions": {
      "ShouldAdd": true,
      "ShouldDelete": false,
      "ShouldUpdate": true
    }
  },
  {
    "Name": "Business",
    "Description": "division with name and color name",
    "Color": "yellow",
    "ExpectedStatus": {
      "WillBeAdded": true,
      "WillBeDeleted": true,
      "WillBeUpdated": true
    },
    "PerformableActions": {
      "ShouldAdd": true,
      "ShouldDelete": false,
      "ShouldUpdate": true
    }
  },
  {
    "Name": "",
    "Description": "division without name and color name, should add white color",
    "Color": "",
    "ExpectedStatus": {
      "WillBeAdded": true,
      "WillBeDeleted": true,
      "WillBeUpdated": true
    },
    "PerformableActions": {
      "ShouldAdd": true,
      "ShouldDelete": true,
      "ShouldUpdate": true
    }
  },
  {
    "Name": "",
    "Description": "without name and color name and will not be added",
    "Color": "black",
    "ExpectedStatus": {
      "WillBeAdded": false,
      "WillBeDeleted": false,
      "WillBeUpdated": false
    },
    "PerformableActions": {
      "ShouldAdd": true,
      "ShouldDelete": false,
      "ShouldUpdate": false
    }
  }
]
我在这里用了两件事:

1。PerformableActions即使用此测试用例数据可以执行哪些操作。例如,shoulldadd表示应执行此测试用例以添加记录,shoullddelete表示应运行此测试用例以删除记录,同样应运行shoulldupdate

2。ExpectedStatus即测试用例的预期结果, WillBeAdded表示将此数据添加到网格中。同样,将删除和更新工作

问题:

1) 我对所有CUD操作使用相同的测试数据,原因是我必须在我的应用程序中保持CUD流。因为只需要测试UI,所以我只是假设创建、检索和删除将按顺序工作

在积垢操作的情况下,这是正确的测试方法吗

2) 假设我必须运行项目中的所有测试,可能是数百个或数千个,我如何维护顺序,因为我可以看到唯一可能的方法是在NUNit中使用顺序属性。我如何使用它,或者是否有任何替代方法来分别测试独立模块组和依赖模块组

  • 你的方法没有错。您可以为每种情况创建一个函数,并按照您希望的顺序生成C、U和D。也许您需要在它们之间添加
    wait
    s,让后端完成这项业务
  • OrderAttribute与NUnit配合使用效果足够好,即使有更好的方法。您还可以列出测试用例并按顺序依次运行它们。为什么不呢?不要局限于类和方法
  • 我知道,你用
    C#
    标记了你的问题,但是对于这么多的工作,也许值得看看你现在没有的其他库。如果你不害怕学习很少,你可以享受F#:

    • 使用,您可以完全控制运行的顺序和测试
    • 与你有一个很好的DSL的硒。下面是一个小例子。你甚至可以在chrome的无头模式下运行它
    • 您甚至可以使用
  • 更新:对于排序,您可以定义自己的属性,甚至可以使用NUnit中的现有属性,并按正确的顺序调用每个反射的方法。或者为测试定义自己的DSL,遍历列表并提取所需的信息

        public struct CRUD
    {
        public bool C;
        public bool R;
        public bool U;
        public bool D;
        public CRUD(bool c, bool r, bool u, bool d)
        {
            this.C = c;
            this.R = r;
            this.U = u;
            this.D = d;
        }
    }
    public enum ActionKind
    {
        Create,
        Read,
        Update,
        Delete
    }
    public struct TestResult
    {
        public ActionKind Action;
        public bool IsPerformed;
    }
    public class TestCase
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string Color { get; set; }
        public CRUD Action { get; set; }
        public List<TestResult> Actual { get; set; }
        public List<TestResult> Expected { get; set; } // or List<TestResult>
    
    }
    public class Tests
    {
        public void TestAListOfCases()
        {
            var cases = new List<TestCase>
            {
                new TestCase { Name = "Finance", Description = "division with complete test data", Color = "#ff0000",
                    Expected = new List<TestResult> {new TestResult {Action = ActionKind.Create, IsPerformed = true },
                                                     new TestResult {Action = ActionKind.Update, IsPerformed = false},
                                                     new TestResult {Action = ActionKind.Delete, IsPerformed = true }
                    }},
                new TestCase { Name = "IT", Description = "Description"}
            };
    
            cases
                .Where(x => x.Name == "IT")
                .Where(x => x.Color != "pink")
                .Select(RunTestCase)
                .Where(x => !x.Item2)
                .Select(x => OutputFailedTestCase(x.Item1)); // boah c# is verbose
        }
        public Tuple<TestCase, bool> RunTestCase(TestCase testCase)
        {
            foreach(var exp in testCase.Expected)
            {
                switch (exp.Action) {
                    case ActionKind.Delete:
                        // do delete if needed and create actual result
                        var actual = exp.IsPerformed
                            ? new TestResult { Action = exp.Action, IsPerformed = true }
                            : new TestResult { Action = exp.Action, IsPerformed = false };
                        break;
    
                }
            }
            var isFailed =
                Enumerable.Zip(
                    testCase.Actual, 
                    testCase.Expected, 
                    (expected, actual) => expected.Action == actual.Action && expected.IsPerformed == actual.IsPerformed)
               .All(x=>x);
            // your selenium stuff
            return Tuple.Create(testCase, isFailed);
        }
        public bool OutputFailedTestCase(TestCase testCase)
        {
            // write to console or do something else
            Console.Write($"{testCase.Name} is failed to perform following actions: {calculateFailedActions}");
            return true;
        }
    }
    
    公共结构积垢
    {
    公共图书馆;
    公共图书馆;
    公共图书馆;
    公共福利;
    公共积垢(bool c、bool r、bool u、bool d)
    {
    这个.C=C;
    这个。R=R;
    这个。U=U;
    这个。D=D;
    }
    }
    公共枚举操作类
    {
    创造,,
    阅读
    更新,
    删除
    }
    公共结构测试结果
    {
    公共行动和善意行动;
    公共事业表现良好;
    }
    公共类测试用例
    {
    公共字符串名称{get;set;}
    公共字符串说明{get;set;}
    公共字符串颜色{get;set;}
    公共CRUD操作{get;set;}
    公共列表实际值{get;set;}
    公共列表应为{get;set;}//或列表
    }
    公开课考试
    {
    公营房屋
    {
    var案例=新列表
    {
    新测试用例{Name=“Finance”,Description=“具有完整测试数据的部门”,Color=“#ff0000”,
    Expected=new List{new TestResult{Action=ActionKind.Create,IsPerformed=true},
    新的测试结果{Action=ActionKind.Update,IsPerformed=false},
    新测试结果{Action=ActionKind.Delete,IsPerformed=true}
    }},
    新测试用例{Name=“IT”,Description=“Description”}
    };
    案例
    .Where(x=>x.Name==“IT”)
    .其中(x=>x.颜色!=“粉色”)
    .Select(RunTestCase)
    .其中(x=>!x.Item2)
    .Select(x=>OutputFailedTestCase(x.Item1));//boah c#冗长
    }
    公共元组RunTestCase(TestCase-TestCase)
    {
    foreach(testCase.exp中的var exp应为)
    {
    开关(exp.Action){
    案例操作种类。删除:
    //如果需要,请删除并创建实际结果
    var实际值=exp.IsPerformed
    ?新的测试结果{Action=exp.Action,IsPerformed=true}
    :newtestresult{Action=exp.Action,IsPerformed=false};
    打破
    }
    }
    isvar失败了=
    可枚举.Zip(
    测试用例,实际的,
    testCase,预期,
    (预期,实际)=>expected.Action==actual.Action&&expected.IsPerformed==actual.IsPerformed)
    .全部(x=>x);
    //你的硒元素
    返回Tuple.Create(testCase,isFailed);
    }
    公共布尔输出失败测试用例(TestCase TestCase)
    {
    //写入控制台或执行其他操作
    Write($“{testCase.Name}无法执行以下操作:{calculateFailedActions}”);
    返回true;
    }
    }
    
    谢谢至少有人调查了我的问题