Test not working well when we try to parallel it

2 posts, 0 answers
  1. Javier
    Javier avatar
    10 posts
    Member since:
    Apr 2013

    Posted 23 Oct 2013 Link to this post

    Hi,

    I have a test that have a Parallel.For in it. If I remove the Parallel.For, works fine, but if I try to do it in a parallel way I get an exception like if the Mocks where not applied.

    Exception:

    Test method Tgw.Wcs.StorageAndInventory.U.Test.Core.LoadCarrierManagerTest.UpdateLoadCarrierLocksLoadCarrier threw exception: 
    System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: No connection string named 'StorageAndInventoryContext' could be found in the application config file.

    Is like after the first thread is launched the rest of them cannot get the Mocked object...

    [TestInitialize]
           public void Initialize()
           {
               loadCarrierManager = new LoadCarrierManager();
               loadCarrier = new LoadCarrier { Name = "LC1" };
               //Creates a number of elements
               loadCarriers = CreateLoadCarriers(numberOfLoadcarriers);
                
               //First Mock the SIS Context
               storageAndInventoryContext = Mock.Create<StorageAndInventoryContext>(() => new StorageAndInventoryContext("Non"),
                                                           Behavior.CallOriginal);
               //Mock the GetContext so it will return out Mocked element
               Mock.Arrange(() => StorageAndInventoryContextProvider.GetContext())
                   .Returns(storageAndInventoryContext);
     
               Mock.Arrange(() => storageAndInventoryContext.InventoryAccountSet.OfType<LoadCarrier>())
                  .ReturnsCollection(loadCarriers);
           }
     
     
     
           [TestMethod]
           [TestCategory(TgwTestingCategories.ServiceTest)]
           [WorkItem(11126)]
           public void UpdateLoadCarrierLocksLoadCarrier()
           {
     
              Parallel.For((long)0, 3, i =>
                   {
                       using (var scope = new UnitOfWorkScope())
                       {
                           for (int lcCount = numberOfLoadcarriers-1; lcCount > 0; lcCount--)
                           {
                               string lcName = string.Format("LC{0}", lcCount);
     
                               LoadCarrierChangeSet loadCarrierChangeSet = new LoadCarrierChangeSet();
     
                               var lcToUpdate = loadCarrierManager.GetLoadCarrierData(lcName);
     
                               loadCarrierChangeSet.Locks = new LockChangeSet("fooReason", "fooDescription");
     
                               loadCarrierManager.UpdateLoadCarrier(lcToUpdate.Name, loadCarrierChangeSet);
                           }
     
                           scope.Complete();
                       }
                 });
     
               using (new UnitOfWorkScope())
               {
     
                   var badEntityLocksDescriptions =
                       storageAndInventoryContext.InventoryAccountSet.OfType<LoadCarrier>()
                                                 .Select(x => x.EntityLocks.Where(y=>y.Description == "fooReason"));
     
     
                   Assert.AreEqual(100, badEntityLocksDescriptions.Count());
               }
           }


    
    
  2. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 25 Oct 2013 Link to this post

    Hi Javier,

    Thank you for contacting us.

    Your conclusion about not applying static mocks in parallel execution is correct.
    For example, take the following:

    We have a static class, like this:
    public static class Foo
    {
        public static string Prop { get; set; }
    }

    Now, we can write the following test:
    [TestMethod]
    public void NormalExecution()
    {
        Mock.Arrange(() => Foo.Prop).Returns("test");
     
        for (int i = 0; i < 3; i++)
        {
            var actual = Foo.Prop;
     
            Assert.AreEqual("test", actual);
        }
    }
    It will work as expected. However, if we use Parallel.For, the test will fail:
    [TestMethod]
    public void ExecutionInParallel()
    {
        Mock.Arrange(() => Foo.Prop).Returns("test");
     
        Parallel.For(0, 3, i =>
        {
            var actual = Foo.Prop;
     
            Assert.AreEqual("test", actual);
        });
    }
    This is because, as noted above, the static arrangement is not applied for all threads.

    One way to make the above test green (to make it pass) is to add the mock creations and their arrangements inside the parallel for, like this:
    [TestMethod]
    public void ExecutionInParallel()
    {
        Parallel.For(0, 3, i =>
        {
            Mock.Arrange(() => Foo.Prop).Returns("test");
     
            var actual = Foo.Prop;
     
            Assert.AreEqual("test", actual);
        });
    }
    This, however is not a good practice as it leads to more complicated and tiresome tests.

    Another way to make this work, is to use a singleton. Below is the a singleton of the previous Foo class:
    public class SingletonFoo
    {
        private static SingletonFoo myInstance = new SingletonFoo();
        private static object syncRoot = new Object();
     
        private SingletonFoo() { }
     
        public static SingletonFoo GetInstance
        {
            get
            {
                if (myInstance == null)
                {
                    lock (syncRoot)
                    {
                        if (myInstance == null)
                            myInstance = new SingletonFoo();
                    }
                }
                return myInstance;
            }
        }
     
        public string Prop { get; set; }
    }

    Now, the parallel unit test works:
    [TestMethod]
    public void ExecutionInParallel()
    {
        var myFoo = SingletonFoo.GetInstance;
        Mock.Arrange(() => myFoo.Prop).Returns("test");
     
        Parallel.For(0, 3, i =>
        {
            var actual = myFoo.Prop;
     
            Assert.AreEqual("test", actual);
        });
    }

    To summarize:
    • Firstly, I do not recommend parallel test execution. It may give performance, but a lot of concurrency issues can occur.
    • If you decide to stick to the parallel test execution, I suggest using singleton classes instead of statics. By far, this is the only reliable way to isolate the different threads.
    • If singleton is not an option for you (e.g.: you may need to refactor a lot of code), you can try adding the mock creations and their arrangements in parallel, as well.

    I hope this gives the required answers. Let me know if I can assist you further.


    Regards,
    Kaloyan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  3. DevCraft R3 2016 release webinar banner
Back to Top