xUnit Testing and InitFixtureBase in Fixture Initialization Error

Eugene Paden asked on April 8, 2022 01:22

I'm using xUnit for creating unit tests and tests are successful when individually run, however, when all tests are run, I get the error below.

Any idea how to fix this?

Message: 
System.InvalidOperationException : Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.

  Stack Trace: 
Dictionary`2.FindValue(TKey key)
Dictionary`2.TryGetValue(TKey key, TValue& value)
AppStateReset.IsCompilerGenerated(Type type)
AppStateReset.TypeIsSupported(Type type)
<>c__DisplayClass1_0`1.<CombinePredicates>b__0(TSource x)
<>c__DisplayClass1_0`1.<CombinePredicates>b__0(TSource x)
WhereEnumerableIterator`1.ToList()
Enumerable.ToList[TSource](IEnumerable`1 source)
AppStateReset.GetFilteredTypes(IEnumerable`1 types)
AppStateReset.EnsureSequence()
AppStateReset.Reset()
AutomatedTests.ResetAppState()
AutomatedTests.InitFixtureBase()

Recent Answers


Eugene Paden answered on April 8, 2022 17:04

I simulated the same tests in nUnit, enabled parallel execution and encountered a similar error:

Message: 
OneTimeSetUp: System.InvalidOperationException : Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. 
0 votesVote for this answer Mark as a Correct answer

Dmitry Bastron answered on April 11, 2022 07:19

Hi Eugene,

Could you please share the code of your tests to provide more context? Quite possibly you are using Dictionary when preparing mock data for tests and this dictionary is used across multiple tests. The system is trying to run these tests in parallel, but it's not possible because your dictionary is not thread-safe. PIf this is the case, consider creating a new instance of Dictionary for every test and not share the same object across multiple tests.

0 votesVote for this answer Mark as a Correct answer

Eugene Paden answered on April 12, 2022 15:16 (last edited on April 12, 2022 15:18)

Hi Dmitry,

The problem seems to be with the CMS.Tests.UnitTests class initialization methods (OneTimeSetup). nUnit tests by default are not run in parallel, while xUnit tets are. I encounter the error with just these 2 sample tests.

[TestFixture]
[Parallelizable(ParallelScope.All)]
public class Tests : UnitTests
{
    [SetUp]
    public void Setup()
    {

        Fake<UserInfo, UserInfoProvider>().WithData(
        new UserInfo[] {
            new UserInfo
            {
                UserID = 123,
                UserName = "FakeUser",
                UserNickName = "FakeUser"
            },
            new UserInfo
            {
                UserID = 124,
                UserName = "FakeUser4",
                UserNickName = "FakeUser4"
            }
        });
    }

    [Test]
    public void Test1()
    {

        var users = UserInfo.Provider.Get().First();


        Assert.NotNull(users);
    }
}

 [TestFixture]
 [Parallelizable(ParallelScope.All)]
internal class PageExtensionsTests : UnitTests
{

    [SetUp]
    public void Setup()
    {
        Fake<TreeNode>();
    }

    [Test]
    public void ToDaysOfWeekTest()
    {


        var friday = TreeNode.New();
        friday.NodeAlias = "Friday";

        var sunday = TreeNode.New();
        sunday.NodeAlias = "Sunday";

        var treeNodes = new List<TreeNode>() { friday, sunday };

        var daysOfWeek =  treeNodes.ToDaysOfWeek();
        Assert.NotNull(daysOfWeek);
        Assert.True(daysOfWeek.Contains(DayOfWeek.Friday));
        Assert.True(daysOfWeek.Contains(DayOfWeek.Sunday)); 
        Assert.False(daysOfWeek.Contains(DayOfWeek.Monday));

    }
}
0 votesVote for this answer Mark as a Correct answer

Eugene Paden answered on April 12, 2022 15:40

Btw, I also looked CMS.Tests.AppStateReset and all the private properties are non-concurrent so looks like we are stuck with non-parallel test execution for now.

 public class AppStateReset
{
    private readonly static Lazy<IEnumerable<AppStateReset.ExcludedField>> EXCLUDED_FIELDS;

    private HashSet<string> mAssembliesToInitialize;

    private HashSet<string> mInitializedAssemblies;

    private readonly HashSet<Type> mKnownGenericTypes = new HashSet<Type>();

    private List<FieldInfo> mFields;

    private List<Type> mInitSequence;

    private readonly static Dictionary<Type, bool> mCompilerGenerated;

    private readonly static Dictionary<FieldInfo, bool> mHasThreadStaticFields;

    private bool mLoaded;

    internal Func<Assembly, bool> AssemblyCondition { get; set; } = new Func<Assembly, bool>(AppStateReset.StartsWithCMSOrKentico);

    ..........................

}

0 votesVote for this answer Mark as a Correct answer

Dmitry Bastron answered on April 13, 2022 06:48

Hi Eugene,

Yes, it appears to be correct. I don't think with the current state of application you will be able to run tests in parallel. However, it's worth writing a note to Kentico Xperience support team to have a look at this issue and probably for one of the next refreshes they can consider this improvement.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.