Unit Test parallel execution of static classes or ServiceLocator

Please note that I am NOT promoting an anti-pattern or code smell here. I know using the service locator or static classes that hold the state or cause the side-effect are not in everyone’s favor but let’s face it. Life is not perfect. What if you happen to be in a decade old legacy project that heavily depends on static classes or service locator pattern? But it shouldn’t stop you from adding the unit tests if you want.

Source Code for Test Project: https://github.com/michaelsync/Michael-Sync-s-blog-sample/tree/master/XunitTestsParallel

Mocking Static Classes

The problem with the static class is that you can’t mock them unless your mocking library supports it. Here is the list of mock libraries (both free and commercial) that supports the static class mocking in .NET world.

Let’s say we are using Microsoft Fakes. You can mock the DateTime.Now as below.

// Shims can be used only in a ShimsContext:
            using (ShimsContext.Create())
            {
              // Arrange:
                // Shim DateTime.Now to return a fixed date:
                System.Fakes.ShimDateTime.NowGet = 
                () =>
                { return new DateTime(fixedYear, 1, 1); };

                // Instantiate the component under test:
                var componentUnderTest = new MyComponent();

              // Act:
                int year = componentUnderTest.GetTheCurrentYear();

              // Assert: 
                // This will always be true if the component is working:
                Assert.AreEqual(fixedYear, year);
            }

It’s pretty easy, huh? What about the service locator?

Mocking Service Locator

Mocking the service locator is very easy as well since it allows us to set the mock locator using

ServiceLocator.SetLocatorProvider()

method.

The example below shows how to mock the service locator using Moq in xunit test.


public class TestClass1 {

        public TestClass1() {
            var mock = new Mock<IDataStore>();
            mock.Setup(m => m.GetData())
                .Returns(1); /* Returns 1 from TestClass1 */

            var mockServiceLocator = new Mock<IServiceLocator>();
            mockServiceLocator.Setup(ms => ms.GetInstance<IDataStore>())
                .Returns(mock.Object);

            ServiceLocator.SetLocatorProvider(() => mockServiceLocator.Object);
        }

        [Fact]
        private void TestClass1TestMethod1() {
            var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
            Assert.Equal<int>(1, data);
        }

        [Fact]
        private void TestClass1TestMethod2() {
            var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
            Assert.Equal<int>(1, data);
        }
}

So far so good. What is the problem?

Test Parallelization

Some test frameworks let you run the tests in parallel. For example, xunit 2.0 which is released early this year (March 16, 2015) has a new feature that let the tests from different classes run in parallel by default. (You can read about it in “Parallelism” in the release note or here “Running Tests in Parallel” ). xUnit 2.0 uses the concepts called “Test Collection” to decide which tests can run against each other in parallel. Each test class is a unique test collection and

ParallelizeTestCollections

property is set to true by default.

So, the tests that has the dependency on server locator or static class will be failed randomly with test parallelization but the test will work fine when you run it individually. Because what you setup in one test will be overridden the setup from different test class so the assertion will be failed when the overrides happens.

I have TestClass1 in my previous example above. I will add another class called TestClass2 to show you te random test failture.

 
public class TestClass2 {
        public TestClass2() {
            var mock = new Mock<IDataStore>();
            mock.Setup(m => m.GetData())
                .Returns(2); /* Returns 2 here */

            var mockServiceLocator = new Mock<IServiceLocator>();
            mockServiceLocator.Setup(ms => ms.GetInstance<IDataStore>())
                .Returns(mock.Object);

            ServiceLocator.SetLocatorProvider(() => mockServiceLocator.Object);
        }

        [Fact]
        private void TestClass2TestMethod1() {
            var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
            Assert.Equal<int>(2, data);
        }

        [Fact]
        private void TestClass2TestMethod2() {
            var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
            Assert.Equal<int>(2, data);
        }
}

Try running all tests a few times after adding the TestClass2. You will see that at least one test out of four tests will be failed randomly. It is because the locator is a static class and what we setup (let’s say we return 1.) in TestClass1 will be overridden by the setup from TestClass2 so the assertion will be failed.

Random Test Failed

How do we fix that?

Initially, I looked at Microsoft Fakes which is shipped with Visual Studio and is also the next generation of Moles. According to the concurrency section of this document, it doesn’t have thread affinity so no go for me.

Shim types apply to all threads in the AppDomain and don’t have thread affinity. This is an important fact if you plan to use a test runner that support concurrency: tests involving shim types cannot run concurrently. This property is not enfored by the Fakes runtime.

Then, I look at Telerik’s JuckMock. The paid version of JuckMock supports what they called “elevated-mocking” that allows you to mock the static class. (Note: The free version “JuckMock Lite” doesn’t support the elevated-mocking. )

So, I refactored my test code as below.


public class TestClass1 {
    private readonly Mock<IServiceLocator> mockServiceLocator;

    public TestClass1() {
        var mock = new Mock<IDataStore>();
        mock.Setup(m => m.GetData())
            .Returns(1);

        mockServiceLocator = new Mock<IServiceLocator>();
        mockServiceLocator.Setup(ms => ms.GetInstance<IDataStore>())
            .Returns(mock.Object);
    }


    [Fact]
    private void TestClass1TestMethod1() {
        Telerik.JustMock.Mock.Arrange<IServiceLocator>(() => ServiceLocator.Current)
            .Returns(mockServiceLocator.Object);

        var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
        Assert.Equal<int>(1, data);
    }

    [Fact]
    private void TestClass1TestMethod2() {
        Telerik.JustMock.Mock.Arrange<IServiceLocator>(() => ServiceLocator.Current)
                        .Returns(mockServiceLocator.Object);

        var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
        Assert.Equal<int>(1, data);
    }
}

public class TestClass2 {
    private readonly Mock<IServiceLocator> mockServiceLocator;

    public TestClass2() {
        var mock = new Mock<IDataStore>();
        mock.Setup(m => m.GetData())
            .Returns(2);

        mockServiceLocator = new Mock<IServiceLocator>();
        mockServiceLocator.Setup(ms => ms.GetInstance<IDataStore>())
            .Returns(mock.Object);
    }

    [Fact]
    private void TestClass2TestMethod1() {
        Telerik.JustMock.Mock.Arrange<IServiceLocator>(() => ServiceLocator.Current)
            .Returns(mockServiceLocator.Object);

        var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
        Assert.Equal<int>(2, data);
    }

    [Fact]
    private void TestClass2TestMethod2() {
        Telerik.JustMock.Mock.Arrange<IServiceLocator>(() => ServiceLocator.Current)
            .Returns(mockServiceLocator.Object);

        var data = ServiceLocator.Current.GetInstance<IDataStore>().GetData();
        Assert.Equal<int>(2, data);
    }
}

Edited: I can’t move Mock.Arrange() to the constructor because I think JustMock has a thread affinity and xunit might use the different thread to call the constructor and test method. That’s why I repeat the code in every test method. End Edited.

Before you run the test, there is a little small thing that you need to do. You need to enable the profiler in Telerik menu.

Enable Profiler

The reason is that JustMock is using the profiling API to enable the elevated mocking. I heard that TypeMock is using the same thing as well. Please read this post if you want to know more about it.

Now, you can run all tests without any failure.

All Tests passed

You can download the sample test project here “https://github.com/michaelsync/Michael-Sync-s-blog-sample/tree/master/XunitTestsParallel“.

That is. Yes. I am not encouraging you to use this feature. If you have the capacity to remove the service locator or static classes from your project then you should probably do that. Otherwise, using the elevated mocking is one way of solving problem.

Tips on compiling NuGetGallery source code and hosting it on IIS

Last week, I tried compiling the source code of NuGetGallery and hosting it on IIS but found some issues. Here is the list of issues/solutions that I found. I am sharing it here. Hope it will save some of your times if you are facing the same issues.

Note that I was using the master branch and the date that I downloaded the source from that branch was 22/09/2015.

Azure SDK

The first error that I got was the compile error. It was because I don’t have an Azure SDK on my VM. Well, I know installing the Azure SDK is one of the prerequisites but I am not going to host it on Azure so I decided to change the path of two assemblies below in NuGetGallery.csproj.

  • Microsoft.WindowsAzure.Diagnostics.dll
  • Microsoft.WindowsAzure.ServiceRuntime.dll

NuGet Gallery team shipped those assemblies under lib/AzureSDK so it’s quite easy to change it.

Wrong Path of Azure DLL

Entity Framework 5 + VS2013 Update 5 issue

I got this error when I tried to update the database.

22-09-2015 1-02-14 PM

It looks like a known issue with EF5+VS2013Update but I found the workaround Update-Database throwing “Could not load file or assembly EntityFramework .. or one of its dependencies” error.

The steps below is the workaround to fix this issue.

  • Start VS Command Prompt as Administrator
  • Go to your packages directory and find the EntityFramework package directory.
  • Go to lib\net45
  • Type: gacutil /i EntityFramework.dll
  • Restart Visual Studio

I managed to update the database after I did those steps but I got the runtime error below when I launch the NuGetGallery project.

Failed to set Database.DefaultConnectionFactory to an instance of the ‘System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework’ type as specified in the application configuration. See inner exception for details.

{“Could not load file or assembly ‘EntityFramework’ or one of its dependencies. The system cannot find the file specified.”:”EntityFramework”}

so I would suggest that you should uninstall EntityFramework.dll from GAC later.

gacutil /u EntityFramework

RequireSsl

It’s up to you whether you want to have SSL enabled or not. For me, I don’t need it so remove [RequireSsl] attribute from NuGetGallery/Controllers/AuthenticationController.cs.

Remove ReWrite

I don’t want to enable http-rewrite module and when I look at the config, it looks like they are just using it for nuget.org only so I removed the whole re-write session from config.

Remove rewrite

Enable-LocalTestMe

If you are running it from VS, you will have to enable the local test me by running .\Enable-LocalTestMe.ps1 script unless you want to change the configuration manually. but your goal is just to host it on IIS then you don’t have to do it.

Enable_localTestMeinIISExpress

NuGet Push “Method Not Allowed” error

After I manage to run NuGetGallery project, I got another small issue with nuget push.

[16:35:45][push] Failed to process request. ‘Method Not Allowed’.
[16:35:45][push] The remote server returned an error: (405) Method Not Allowed..
[16:35:45][push] Process exited with code 1
[16:35:45][Step 6/6] Step Push To NuGet (NuGet Publish) failed

I removed “WebDEV” from http-handler and module. After that, it works.

 

 

WebDev

I will probably upload the publish file and database schedule later this week or next week.

Copy and Paste problem between local and remote computer during Remote Desktop connection?

Microsoft Remote Desktop Connection

Okie. We use the remote desktop connection everyday and we all know that we need to enable “Clipboard” option in “Local Resources” in RPP to support copy/paste between local machine and remote. But sometimes, this copy/paste thing suddenly stop working and you will end up keep on disconnecting and connecting the remote desktop connection again and again.

Microsoft Remote Desktop Connection Resource Clipboard

Sound familiar? I want to share the solution that works for me. When you got this copy/paste issue, you open up the task manager, kill the rdpclip.exe under your name. Then you can run rdpclip.exe again from Task manager or commandline. After that, you can try to copy/paste again. Let me know if it doesn’t work for you.

Windows Task Manager

Teamcity Tip: Building all pull requests and updating the status to Github

I like to share a must-have tip for those who are using continuous integration/continuous delivery with github and teamcity.

Merging all pull requests and build all branches

Let’s talk about how we work with github. We keep the master as a stable branch and if we need to work on new feature or bug fixes, we create another branch and push it as a pull request once we’ve done the job. So, another guy can review the code and merge it to the stable branch. The challenge here is that we like to know whether there is any conflict or test failtures before we merge the code or not. Do we have to pull the latest, merge the code manually and run the tests to see the result? Would it be nice if your CI can tell you automatically after you’ve done your pull request?

if the answer is yes, here  is the solution for you. In the version control setting of your TeamCity project configuration, you can specify the branch specification. All you need to do  is adding two lines as below in “Branch specification” textbox and trigger the “run” button again.

Github - Merge all pull request and build them all

You will see the statuses of all branches (including merges) in your Teamcity dash board. pretty cool, huh? But of course, you will have to open your TeamCity home page to see the results. Would it be even nicer if you can see it on github itseft?

Github - Merge all pull request and build them all on TeamCity

Updating the commit status to Github

Github provides us the API for updating the commit status. Please refer to this official post “Commit Status API” for details.

status-001-20120830-161640

Don’t worry! You don’t have to worry about reading the spec or writing any code for it.  There is an awesome Teamcity plugin “TeamCity.GitHub” written Eugene Petrenko. You can download this plugin from his github repository and build it by yourself or you can just download it as zip file from TeamCity’s build artifact.

Step #1: And then put that zip file (No! don’t need to extract it) to <TeamCity Data Directory>/plugins. if you are not sure whether that folder is then you can check about it in your TeamCity Global setting page.

TeamCity - Global Setting

Step #2: Please restart the teamcity service

Step #3: Go to your team city project configuration => Build Steps. And click on “Add build feature” button. You will see the dialog below and select “Report change status to GitHub“.

Add Build Feature

Step #4: Fill up the required information such as user name, password, repository and etc. You can use the same URL that I mentioned in my screenshot unless you are using GitHub Enterprise.

Report change status to Github

Then, Good to go!

If your pull request is in good shape, you will see something like that at the bottom of your pull request in github.

your pull request is cool

Otherwise, you will get this. meaning you will have to do some manual works.

your pull request is bad for now

Ok. That’s all I know.. and that’s how we are using it.. If any feedback or comment, please shot.. Thanks!

Visual Studio 2013 + SlowCheetah error

I got this error recently when I tried to rebuild the project that I downloaded from github in VS2013.

Error Message:

Error 1 The “SlowCheetah.Xdt.TransformXml” task could not be loaded from the assembly C:\Users\Michael\AppData\Local\Microsoft\MSBuild\SlowCheetah\v2.5.10.2\SlowCheetah.Xdt.dll. Could not load file or assembly ‘file:///C:\Users\Michael\AppData\Local\Microsoft\MSBuild\SlowCheetah\v2.5.10.2\SlowCheetah.Xdt.dll’ or one of its dependencies. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask. Project-Name

Error Screenshot

SlowCheatch

Here is the solution that works for me. Of course, feel free to share if you have alternative solution or better one.

Solution

  • Close Visual Studio 2013 (if it’s opened)
  • Delete SlowCheetah package in %userprofile%\AppData\Local\NuGet\Cache

Cache

  • Delete all folders under this path %userprofile%\AppData\Local\Microsoft\MSBuild\SlowCheetach

 

MSBuild

 

That’s all. It works for me. If it’s not working for you or you have other solution, please drop a comment. Thanks!

WebDeploy 3 – Error in publishing website to Amazon EC2

Here is the error that I got when I publish website from Azure VM to Amazon EC2 VM. I am using the following MSBuild command to do the deployment and I got Web Deploy 3.0 installed on EC2 VM.

/p:Configuration=Release /p:OutputPath=bin /p:VisualStudioVersion=11.0 /p:DeployOnBuild=True /p:DeployTarget=MSDeployPublish /p:MsDeployServiceUrl=https://my-super-cool-server/msdeploy.axd /p:AllowUntrustedCertificate=True /p:DeployIisAppPath=YourWebSiteInstanceName /p:MSDeployPublishMethod=WMSVC /p:username=root /p:password=SuperComplexRootPassword

Error Message [VSMSDeploy] C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets(4196, 5): error ERROR_DESTINATION_NOT_REACHABLE: Web deployment task failed. (Could not connect to the remote computer (my-super-cool-server””). On the remote computer, make sure that Web Deploy is installed and that the required process (“Web Management Service”) is started. Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_DESTINATION_NOT_REACHABLE.) [14:58:46][MyWebsite\MyWebsite.csproj.teamcity] Project MyWebsite\MyWebsite.csproj.teamcity failed. VSMSDeploy-update Solution As this post is not about how to use WebDeploy to deploy website, I am not going to write the detailed steps here. If you are new to using webdeploy, please read this post “Automating Deployment with Microsoft Web Deploy” The reason that I got this error is that the default for Web Management Service is not enabled by default in EC2. The solution is to enable the port 80 (which you might already enabled it for your website) for Web Deployment Agent and port 8172 for Web Management Service in both the server’s firewall and EC2 Security Group.

  • Web Deployment Agent Service : Port 80
  • Web Management Service : Port 8172

EC2 Security Group Hope it helps for those who are using MS deploy for publishing website on IIS. Reference: