【问题标题】:Clean Up after Canceling tests取消测试后清理
【发布时间】:2015-08-27 12:06:50
【问题描述】:

我目前正在通过 Visual Studio 运行测试。在运行所有测试之前,我会自动创建一定数量的具有已知凭据的用户,并在运行结束时删除这些用户。但是,有时我需要中途取消我的测试。在这些情况下,测试永远没有机会清理,这意味着测试运行中留下了虚假的用户信息,并可能导致下一次测试运行崩溃(当它试图将用户信息添加到数据库中时)。即使取消测试,是否有强制 Visual Studio/mstest 运行清理方法?

我知道一种选择是进行测试检查并确保用户信息不存在,如果它确实在创建新用户之前将其删除。但这仍然不能解决取消测试运行留下不需要的测试数据的问题。

更新:

很抱歉传达错误,但是在测试开始时清理数据不是一种选择。我对这个问题给出了一个非常简单的看法,但简单地说,我没有简单的方法来确保在测试开始时不存在测试数据。所有清理都必须在测试结束时进行。

【问题讨论】:

  • 我会订阅一个事件处理程序,它会在您取消或自然完成时触发,并在这种情况下进行清理
  • 如果在测试运行之前执行清理会怎样?
  • 为什么不能在测试前删除数据?这是您唯一的选择,因为从调试器中取消测试会停止所有执行
  • @SamHolder 一旦测试停止,我就无法获取数据。我可以手动删除它,但是使用我拥有的工具,此时我无法通过我的代码真正删除它,这就是为什么我想在可能的情况下取消测试后删除它。
  • 我不确定您为什么要区分“测试开始”和“测试结束”。在任何两次运行之间,这些本质上是相同的。你说你可以手动删除测试数据——这涉及到什么?

标签: c# visual-studio visual-studio-2013 mstest specflow


【解决方案1】:

在创建数据之前也要进行清理,这将确保无论发生什么都没有剩余数据。当然,这只有在您能够在运行设置之前识别出任何剩余数据的情况下才有可能。

【讨论】:

    【解决方案2】:

    我没有在测试结束时调用清理函数,而是在每个测试开始时调用我的函数,以解决这个确切的问题。

    【讨论】:

      【解决方案3】:

      我认为您应该在测试之前打开一个事务,创建数据并完成测试测试。但不要提交事务。这将确保测试根本不会影响您的数据库。

      更新: 更简单的方法是使用 docker 容器。 您可以从映像运行容器并在测试完成后删除该容器。这肯定会降低测试的复杂性。

      【讨论】:

      • 这没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review
      • 仍然不知道为什么这个问题会被否决而没有任何评论解释原因。我对这个问题的解决方案是将测试中的所有内容都包装在一个事务中,这可以防止测试将数据保存到数据库。仍然不知道为什么它没有提供答案。
      • 您认为 OP 描述您无法以干净的方式回滚事务。根据我的经验,来自连接池的连接在应用程序进程停止后仍会挂起一段时间。在这种情况下,事务是否仍会运行并持有锁?
      【解决方案4】:

      Visual Studio 使用 NUNIT,因此您可以使用 TearDownAttribute。它应该在测试之后运行,即使测试被取消。您可以编写一个函数来清理您的数据。

      请在此处阅读参考文档:http://nunit.org/docs/2.2/teardown.html

      【讨论】:

      • 请不要将“you”缩写为“U”。 StackOverflow 的目标是尽可能专业和国际化。虽然您可能很容易理解,但来自印度尼西亚的非母语人士可能会遇到问题。
      • 谢谢 MechMK1。
      【解决方案5】:

      只是为了进一步了解 NUNIT 标准。请按照Test类中的步骤操作:

      [TestFixture]
      public class _TestClass
      {
              [TestFixtureSetUp]
              public void Setup()
              {
                 //Clearup can be here before start of the tests. But not Recommended
              }
      
              [Test]
              public void _Test1()
              {
              }
              [Test]
              public void _Test2()
              {
              }
      
              [TestFixtureTearDown]
              public void CleanUp()
              {
                  //I will recommend to clean up after all the tests complete
              }
      }
      

      参考:http://nunit.org/docs/2.5/fixtureTeardown.html

      【讨论】:

        【解决方案6】:

        那是不可能的。您最好找到一种替代解决方案,例如使用单独的数据库进行测试并在每次测试运行之前清理所有数据,使用固定的测试用户集或用一些标志标记测试数据。查看 Jimmy Bogard 的 Isolating database data in integration tests 文章。

        没有内置方法可以更改 MSTest 默认行为。理论上,您可以编写利用TestExecution.OnTestStopping 事件的 MSTest 扩展,但这不是一个简单的过程,它需要更改注册表。此外,很多人抱怨它不起作用。

        还有 MSTest V2,一个新版本的 MSTest,具有新的扩展点。但看起来你不能用这一点改变取消行为,只能写属性装饰器。见Extending MSTest V2

        您不能使用AppDomain.CurrentDomain.ProcessExitProcess.GetCurrentProcess().Exited 事件,因为取消似乎会终止测试运行进程。

        NUnit 目前也不支持这个。请参阅相关的 NUnit 测试适配器 Run TearDowns on VS Cancel Test Run 问题。

        【讨论】:

        • 感谢大家的所有新答案。很明显,有些在特定情况下会很好地工作,而在其他情况下则不会。对于我目前的情况,这个答案最接近我现在所需要的。
        【解决方案7】:

        在 ATP 中分配资源时需要考虑两种情况(资源可能是创建用户、与数据库连接)。他们是

        • 每次测试后创建和删除资源。
        • 在一组测试之后创建和删除资源。

        每次测试后创建和删除资源:

        如果我们想在执行 a 测试之前创建特定对象的实例,并且想要在执行该测试之后清理分配给该对象的内存,那么我们使用Test SetUpTest TearDown NUnit 的属性。在您的情况下,对象是创建用户数。

        [SetUp] : 用 Test SetUp 属性修饰的函数包含在执行 any test 之前执行的一段代码。

        [TearDown] : 用 Test TearDown 属性修饰的函数包含在执行任何测试后执行的一段代码

        实施:

        [TestClass]
            public class UnitTest1
            {
                [SetUp]
                public void SetUP()
                {
                    // Creating Users with proper credentials
                }
        
                [TestMethod]
                public void TestMethod1()
                {
                    //Write your ATP
                }
        
                [TearDown]
                public void TearDown()
                {
                    //Clean up
                }
            }
        

        在一组测试后创建和删除资源:

        现在,如果我们想为一组测试创建一个对象的实例,并且想在执行所有测试后清理内存,那么[TestFixtureSetUp][TestFixureTearDown] 来初始化一个对象并清理分别向上记忆。同样,在您的情况下,对象可以是创建用户集。

        [TestFixtureSetUp] :用TestFixtureSetUp 装饰的函数将在执行一组测试之前执行一次。

        [TestFixtureTearDown] : 用TestFixtureTearDown 装饰的函数将在执行一组测试之后执行一次。

        实施

        [TestFixture]
        public class Tests
        {
                [TestFixtureSetUp]
                public void Setup()
                {
                   //Create users with credentials
                }
        
                [Test]
                public void _Test1()
                {
                  //Test_1
                }
                [Test]
                public void _Test2()
                {
                 //Test2
                 }
        
                [TestFixtureTearDown]
                public void CleanUp()
                {
                    //Cleanup; Here you need to add code to Delete all users
                }
        }
        

        注意:我建议您,如果您尝试为特定 ATP 创建和删除用户,请使用 SetUpTearDown。如果您正在为一堆 ATP 尝试相同的方法,我建议您使用 TestFixtureSetUpTestFixtureTearDown

        “如果您的测试通过或失败,SetUp 和 TearDown 函数将执行”

        参考文献:

        【讨论】:

          【解决方案8】:

          使用所谓的“数据库模拟”来更好地解决该问题。在这种情况下,您将使用不同的数据库(或假的虚拟数据库)运行测试。

          本文解释了如何在 C# 中实现它
          https://msdn.microsoft.com/en-us/library/ff650441.aspx

          【讨论】:

            【解决方案9】:

            这个想法是在测试开始之前初始化事务。为了将数据保存在数据库中,必须提交事务,但不是永远不会提交。它在测试时停止,在测试成功或不成功完成的情况下起作用。

            在集成测试中,我们使用这样的东西(使用 NUnit)(它是真正的生产代码)

            public class RollbackAttribute : TestAttribute, ITestAction
            {
                private TransactionScope _transaction;
            
                public void BeforeTest(ITest test)
                {
                    _transaction = new TransactionScope();
                }
            
                public void AfterTest(ITest test)
                {
                    _transaction.Dispose();
                }
            
                public ActionTargets Targets => ActionTargets.Test;
            }
            
            [TestFixture]
            public class SomeTestClass
            {
                [Rollback] //No need [Test] because Rollback is inherit it.
                public void SomeTestMethod()
                {
                }
            }
            

            在 MsTest 上,您可以制作类似的东西,但在这种情况下,您应该从基类继承,我希望它有效。例如:

            public class RollbackTestBase
            {
                private TransactionScope _transaction;
            
                [TestInitialize]
                public virtual void Setup()
                {
                    _transaction = new TransactionScope();
                }
            
            
                [TestCleanup]
                public virtual void TearDown()
                {
                    _transaction.Dispose();
                }
            }
            
            [TestClass]
            public class IntegrationTest : RollbackTestBase
            {
                [TestMethod]
                public void TestDataBase()
                {
                    Assert.IsTrue(true);
                }
            
                [TestInitialize]
                public virtual void Init()
                {
                }
            
                [TestCleanup]
                public virtual void CleanUp()
                {
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多