首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为工作流创建自动化测试

如何为工作流创建自动化测试
EN

Stack Overflow用户
提问于 2020-05-26 10:58:39
回答 1查看 128关注 0票数 0

我正在进行一个工作流项目,该项目有19个测试整个系统的场景和34个步骤。

所以,我的问题是,我如何为它创建一个自动化测试?

我目前的方法是:为每个场景创建一个集成测试,然后创建主系统测试来运行所有集成测试。

代码语言:javascript
复制
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Project1
{
     // Unit tests
    public class UnitTest_step1
    {
        public void RunTest() { }
    }

    public class UnitTest_step2
    {
        public void RunTest() { }
    }

    public class UnitTest_step3
    {
        public void RunTest() { }
    }

    public class UnitTest_step4
    {
        public void RunTest() { }
    }
     // End of unit tests

    public class IntegrationTests
    {

        public void IntegrationTest1()
        {
            UnitTest_step1.RunTest();
            UnitTest_step2.RunTest();
            UnitTest_step4.RunTest();
        }

        public void IntegrationTest2()
        {
            UnitTest_step1.RunTest();
            UnitTest_step2.RunTest();
            UnitTest_step3.RunTest();
            UnitTest_step4.RunTest();
        }

        public void IntegrationTest3()
        {
            UnitTest_step1.RunTest();
            UnitTest_step4.RunTest();
        }

    }



    [TestClass]
    public class SystemTests
    {
        [TestMethod]
        public void Scenario1()
        {
            IntegrationTests.IntegrationTest1()
        }

        [TestMethod]
        public void Scenario2()
        {
            IntegrationTests.IntegrationTest2();
        }

        [TestMethod]
        public void Scenario3()
        {
            IntegrationTests.IntegrationTest3();
        }

        [TestMethod]
        public void ScenarioN()
        {
            IntegrationTests.IntegrationTestN();
        }
    }
}

诚挚的问候。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-28 19:24:02

嗯,在我看来,你的问题中提供的信息是非常抽象的,这个问题有点过于宽泛。答案取决于您的工作流引擎是如何实现的,以及您的系统需求是什么。需求和实现细节定义了您的测试方法。

首先,我将澄清您有哪些步骤,是否传递了任何数据上下文,这些步骤产生了什么副作用(向数据库写入数据、发送事件、调用其他系统API等等)、相互依赖的步骤等等。

另一个问题是,在每一步之后还是在场景之后,您需要如何断言结果?系统应该是可测试的,并且通常,每个步骤都应该包含单元测试。因此,建议的假设方法是用独立的单元测试和集成测试来覆盖每个步骤。

我想出了一个简单的例子来说明一种一般的方法。为了简单起见,我假设步骤很少或没有数据上下文,可以重新排序。

代码语言:javascript
复制
namespace Workflow.Test
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System;
    using System.Collections.Generic;

    [TestClass]
    public class SystemTests
    {
        [TestMethod]
        public void Scenario1()
        {
            new Workflow().Run(new Scenario1());
        }

        [TestMethod]
        public void Scenario2()
        {
            new Workflow().Run(new Scenario2());
        }

        // The advantage of explicit steps declaration is test readability.
        // Declarative approach also enables the further possibility of test generation!
        [TestMethod]
        public void MoreExplicitAndDeclarative()
        {
            new Workflow().Run(new List<Type>
            {
                typeof(Step1),
                typeof(Step2),
                typeof(Step3),
            });
        }

        // Step instantiation may be needed if you want to parameterize some steps.
        [TestMethod]
        [DataRow("Custom step")]
        [DataRow("Another step")]
        public void MoreExplicitParameterizedScenario(string customName)
        {
            new Workflow().Run(new List<IRunnable>{
                new Step1(),
                new Step3(customName)
            });
        }
    }

    [TestClass]
    public class StepsUnitTests
    {
        [TestMethod]
        public void Step1DoesWhatWeWant()
        {
            // Mock dependencies

            new Step1().Run();

            // Assert results
        }
    }

    #region Workflow Engine Example

    public interface IRunnable
    {
        void Run();
    }

    public class Workflow
    {
        public void Run(Scenario scenario)
        {
            Run(CreateSteps(scenario.GetStepTypes()));
        }

        public void Run(IEnumerable<Type> stepTypes)
        {
            Run(CreateSteps(stepTypes));
        }

        public void Run(List<IRunnable> steps)
        {
            steps.ForEach(step => step.Run());
        }

        private List<IRunnable> CreateSteps(IEnumerable<Type> stepTypes)
        {
            var steps = new List<IRunnable>();
            foreach (var stepType in stepTypes)
            {
                steps.Add(CreateStep(stepType));
            }

            return steps;
        }

        private IRunnable CreateStep(Type stepType)
            => (IRunnable) Activator.CreateInstance(stepType);
    }

    #endregion


    // Step structure can differ according to system requirements.
    // We may add data context and link steps into pipeline if needed.
    #region Steps

    public abstract class Step : IRunnable
    {
        private readonly string _stepName;

        protected Step(string name)
        {
            _stepName = name;
        }

        public void Run()
        {
            Console.WriteLine($"{_stepName} in action.");
            Invoke();
        }

        public abstract void Invoke();
    }

    public class Step1 : Step
    {
        public Step1() : base(nameof(Step1))
        {
        }

        public override void Invoke()
        {
            // do work
            Console.WriteLine($"Step1 invoked.");
        }
    }

    public class Step2 : Step
    {
        public Step2() : base(nameof(Step2))
        {
        }

        public override void Invoke()
        {
            // do work
            Console.WriteLine($"Step2 invoked.");
        }
    }

    public class Step3 : Step
    {
        public Step3(string customName) : base(customName)
        {

        }

        public Step3() : this(nameof(Step3))
        {
        }

        public override void Invoke()
        {
            // do work
            Console.WriteLine($"Step3 invoked.");
        }
    }

    public class Step4 : Step
    {
        public Step4() : base(nameof(Step4))
        {
        }

        public override void Invoke()
        {
            // do work
            Console.WriteLine($"Step4 invoked.");
        }
    }

    #endregion

    // Scenarios should be as declarative as possible.
    // Let's say the scenario is just specification of what steps (step Type)
    // and in what order should be executed (List as a non-unique ordered collection).
    #region Scenarios

    public abstract class Scenario
    {
        public abstract List<Type> GetStepTypes();
    }

    public class Scenario1 : Scenario
    {
        public override List<Type> GetStepTypes()
            => new List<Type>
            {
                typeof(Step1),
                typeof(Step2),
                typeof(Step3)
            };
    }

    public class Scenario2 : Scenario
    {
        public override List<Type> GetStepTypes()
            => new List<Type>
            {
                typeof(Step1),
                typeof(Step2),
                typeof(Step4)
            };
    }

    #endregion
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62020604

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档