使用Selenium和NUnit测试执行顺序进行UI自动化测试

时间:2017-05-22 11:07:49

标签: c# selenium-webdriver automated-tests nunit qa

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

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

我的应用程序属于企业级别,已在开发中重建3年。它是一个项目和投资组合管理系统。

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

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

Project structure

我使用以下格式的测试数据作为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 ,即使用此测试用例数据可以执行哪些操作。 E.g shouldAdd表示应该执行此TestCase以添加记录,shouldDelete表示应该运行此testCase以删除记录,类似于shouldUpdate运行。

2。 ExpectedStatus ,即测试用例的预期结果, WillBeAdded意味着将这些数据添加到网格中。同样,WillBeDeleted和WillBeUpdated工作。

问题:

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

这是在CRUD操作情况下进行测试的正确方法吗?

2)认为我必须在我的项目中运行所有测试,它可能数百或数千,我如何维护订单,因为我可以看到唯一可行的方法是使用< NUNit 中的strong>订单属性。我如何使用它或者是否有任何替代方案单独测试独立模块和相关模块组?

1 个答案:

答案 0 :(得分:1)

  1. 你的方法没有错。您可以为每个案例创建一个函数,并按照您希望的顺序生成C,U和D.也许你需要在它们之间添加wait来让后端做它有事业的东西。
  2. 使用NUnit的OrderAttribute工作得很好,即使有更好的方法。您还可以创建测试用例列表并连续按顺序运行它们。为什么不?不要局限于课程和方法。
  3. 我知道,您使用C#标记了您的问题,但是对于这项工作量,可能值得查看一些其他库而不是您现在的库。如果你不怕学习很少,你可以享受F#:

    • 使用Expecto您可以完全控制您的订单和运行的测试
    • Canopy你有一个很好的DSL硒。这是starter kit的例子。你甚至可以在无头模式下使用chrome docker运行它
    • 您甚至可以使用Json Type Provider
    • 获取Json测试定义的智能感知
  4. UPDATE :对于排序,您可以定义自己的属性,甚至可以使用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;
        }
    }