Skip to content

Execute OneTimeTearDown as early as possible when running fixtures in parallel #2335

@jtomkiew-ITM

Description

@jtomkiew-ITM

NUnit 3.7.1

Setup:

Running fixtures in parallel (Parallelizable(ParallelScope.Fixtures) set in AssemblyInfo.cs) in at least 2 threads (LevelOfParallelism(2) set in AssemblyInfo.cs).

Multiple fixtures with tests and OneTimeTearDown's for each of them exist.

Problem:

All [OneTimeTearDown] methods are executed in bulk when first available thread finishes.

Example:

Tests:
using System.Threading;
using NLog;
using NUnit.Framework;

namespace Skanska.Korab2.UITests.Infrastructure.Tests
{
    class Common
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        public static void LogMe(string message)
        {
            Logger.Log(LogLevel.Info, $"{message} from {Thread.CurrentThread.Name}");
        }
    }

    class Class1Fast
    {
        [Test]
        public void Test1()
        {
            Common.LogMe(nameof(Test1));
        }

        [Test]
        public void Test11()
        {
            Common.LogMe(nameof(Test11));
        }

        [OneTimeTearDown]
        public void Test1TearDown()
        {
            Common.LogMe(nameof(Test1TearDown));
        }
    }

    class Class2Slow
    {
        [Test]
        public void Test2()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test2));
        }

        [Test]
        public void Test22()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test22));
        }

        [OneTimeTearDown]
        public void Test2TearDown()
        {
            Common.LogMe(nameof(Test2TearDown));
        }
    }

    class Class3Slow
    {
        [Test]
        public void Test3()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test3));
        }

        [Test]
        public void Test33()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test33));
        }

        [OneTimeTearDown]
        public void Test3TearDown()
        {
            Common.LogMe(nameof(Test3TearDown));
        }
    }

    class Class4
    {
        [Test]
        public void Test4()
        {
            Common.LogMe(nameof(Test4));
        }

        [Test]
        public void Test44()
        {
            Common.LogMe(nameof(Test44));
        }

        [OneTimeTearDown]
        public void Test4TearDown()
        {
            Common.LogMe(nameof(Test4TearDown));
        }
    }

    class Class5
    {
        [Test]
        public void Test5()
        {
            Common.LogMe(nameof(Test5));
        }

        [Test]
        public void Test55()
        {
            Common.LogMe(nameof(Test55));
        }

        [OneTimeTearDown]
        public void Test5TearDown()
        {
            Common.LogMe(nameof(Test5TearDown));
        }
    }

    class Class6
    {
        [Test]
        public void Test6()
        {
            Common.LogMe(nameof(Test6));
        }

        [Test]
        public void Test66()
        {
            Common.LogMe(nameof(Test66));
        }

        [OneTimeTearDown]
        public void Test6TearDown()
        {
            Common.LogMe(nameof(Test6TearDown));
        }
    }

    class Class7
    {
        [Test]
        public void Test7()
        {
            Common.LogMe(nameof(Test7));
        }

        [Test]
        public void Test77()
        {
            Common.LogMe(nameof(Test77));
        }

        [OneTimeTearDown]
        public void Test7TearDown()
        {
            Common.LogMe(nameof(Test7TearDown));
        }
    }

    class Class8Slow
    {
        [Test]
        public void Test8()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test8));
        }

        [Test]
        public void Test88()
        {
            Thread.Sleep(1000);
            Common.LogMe(nameof(Test88));
        }

        [OneTimeTearDown]
        public void Test8TearDown()
        {
            Common.LogMe(nameof(Test8TearDown));
        }
    }
}
AssemblyInfo.cs
[assembly: Parallelizable(ParallelScope.Fixtures)]
[assembly: LevelOfParallelism(2)]
Result:
2017-07-28 18:09:03.0068|INFO|   Test1 from Worker#2
2017-07-28 18:09:03.0338|INFO|   Test11 from Worker#2
2017-07-28 18:09:03.8560|INFO|   Test2 from Worker#1
2017-07-28 18:09:04.0419|INFO|   Test3 from Worker#2
2017-07-28 18:09:04.8612|INFO|   Test22 from Worker#1
2017-07-28 18:09:04.8732|INFO|   Test4 from Worker#1
2017-07-28 18:09:04.8732|INFO|   Test44 from Worker#1
2017-07-28 18:09:04.8862|INFO|   Test5 from Worker#1
2017-07-28 18:09:04.8862|INFO|   Test55 from Worker#1
2017-07-28 18:09:04.8982|INFO|   Test6 from Worker#1
2017-07-28 18:09:04.8982|INFO|   Test66 from Worker#1
2017-07-28 18:09:04.9132|INFO|   Test7 from Worker#1
2017-07-28 18:09:04.9132|INFO|   Test77 from Worker#1
2017-07-28 18:09:05.0482|INFO|   Test33 from Worker#2
2017-07-28 18:09:05.0522|INFO|   Test1TearDown from Worker#2
2017-07-28 18:09:05.0522|INFO|   Test2TearDown from Worker#2
2017-07-28 18:09:05.0677|INFO|   Test4TearDown from Worker#2
2017-07-28 18:09:05.0677|INFO|   Test5TearDown from Worker#2
2017-07-28 18:09:05.0677|INFO|   Test6TearDown from Worker#2
2017-07-28 18:09:05.0677|INFO|   Test7TearDown from Worker#2
2017-07-28 18:09:05.0677|INFO|   Test3TearDown from Worker#2
2017-07-28 18:09:05.9266|INFO|   Test8 from Worker#1
2017-07-28 18:09:06.9321|INFO|   Test88 from Worker#1
2017-07-28 18:09:06.9321|INFO|   Test8TearDown from Worker#1
Expected result:

Test1TearDown is run before Worker#2 has started tests from other fixtures.

Previous versions:

Logs from NUnit 3.6.1:

2017-07-28 18:18:19.3493|INFO|   Test1 from Worker#2
2017-07-28 18:18:19.3913|INFO|   Test11 from Worker#2
2017-07-28 18:18:19.4018|INFO|   Test1TearDown from Worker#2
2017-07-28 18:18:19.9824|INFO|   Test2 from Worker#1
2017-07-28 18:18:20.4252|INFO|   Test3 from Worker#2
2017-07-28 18:18:20.9884|INFO|   Test22 from Worker#1
2017-07-28 18:18:20.9914|INFO|   Test2TearDown from Worker#1
2017-07-28 18:18:20.9914|INFO|   Test4 from Worker#1
2017-07-28 18:18:20.9914|INFO|   Test44 from Worker#1
2017-07-28 18:18:21.0085|INFO|   Test4TearDown from Worker#1
2017-07-28 18:18:21.0085|INFO|   Test5 from Worker#1
2017-07-28 18:18:21.0224|INFO|   Test55 from Worker#1
2017-07-28 18:18:21.0224|INFO|   Test5TearDown from Worker#1
2017-07-28 18:18:21.0224|INFO|   Test6 from Worker#1
2017-07-28 18:18:21.0424|INFO|   Test66 from Worker#1
2017-07-28 18:18:21.0424|INFO|   Test6TearDown from Worker#1
2017-07-28 18:18:21.0574|INFO|   Test7 from Worker#1
2017-07-28 18:18:21.0574|INFO|   Test77 from Worker#1
2017-07-28 18:18:21.0724|INFO|   Test7TearDown from Worker#1
2017-07-28 18:18:21.4422|INFO|   Test33 from Worker#2
2017-07-28 18:18:21.4452|INFO|   Test3TearDown from Worker#2
2017-07-28 18:18:22.0818|INFO|   Test8 from Worker#1
2017-07-28 18:18:23.0879|INFO|   Test88 from Worker#1
2017-07-28 18:18:23.0879|INFO|   Test8TearDown from Worker#1

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions