Monthly Archives: July 2013

TDD: Mocking System.Net.WebClient

Writing unit-test for the class that uses System.Net.WebClient, I have found out that there is no possibility to mock System.Net.WebClient using dynamic mock object frameworks (like RhinoMocks and Moq) because its methods are not virtual.

The solution is to introduce web client interface and abstract factory interface to create such web clients.

interface IWebClient : IDisposable
{
    // Required methods (subset of `System.Net.WebClient` methods).
    byte[] DownloadData(Uri address);
    byte[] UploadData(Uri address, byte[] data);
}

interface IWebClientFactory
{
    IWebClient Create();
}

The default implementations for System.Net.WebClient are straight-forward:

/// <summary>
/// System web client.
/// </summary>
public class SystemWebClient : WebClient, IWebClient
{

}

/// <summary>
/// System web client factory.
/// </summary>
public class SystemWebClientFactory : IWebClientFactory
{
    #region IWebClientFactory implementation

    public IWebClient Create()
    {
        return new SystemWebClient();
    }

    #endregion
}

Now IWebClientFactory interface can be injected as a dependency (constructor injection) and the dependent classes can be tested.

Enjoy!

FreeBSD: MonoDevelop to run NUnit tests

I have spent some hours to figure out why MonoDevelop (4.0.9, bsd-sharp) is unable to run NUnit tests on FreeBSD.
The symptom: the MonoDevelop IDE tries to run the tests and after some time interval shows that no tests were run and there are no test results.

Here is the listing of the test result (test-results directory of the test project):

<?xml version="1.0" encoding="utf-8"?>
<TestRecord xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Results>
    <UnitTestResult>
      <TestDate>2013-07-23T09:08:56</TestDate>
      <Status>Failure</Status>
      <Passed>0</Passed>
      <Errors>0</Errors>
      <Failures>0</Failures>
      <Inconclusive>0</Inconclusive>
      <NotRunnable>0</NotRunnable>
      <Skipped>0</Skipped>
      <Ignored>0</Ignored>
      <Time />
      <Message>Couldn't create a remote process.</Message>
      <StackTrace>  at MonoDevelop.Core.Execution.ProcessHostController.CreateInstance (System.String assemblyPath, System.String typeName, System.String[] addins, IList`1 userAssemblyPaths) [0x00064] in /usr/tmp/usr/ports/devel/monodevelop/work/monodevelop-4.0.9/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs:225 
  at (wrapper remoting-invoke-with-check) MonoDevelop.Core.Execution.ProcessHostController:CreateInstance (string,string,string[],System.Collections.Generic.IList`1&lt;string&gt;)
  at MonoDevelop.Core.Execution.ProcessService.CreateExternalProcessObject (System.Type type, IExecutionHandler executionHandler, IList`1 userAssemblyPaths) [0x0002f] in /usr/tmp/usr/ports/devel/monodevelop/work/monodevelop-4.0.9/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs:343 
  at MonoDevelop.NUnit.NUnitAssemblyTestSuite.RunUnitTest (MonoDevelop.NUnit.UnitTest test, System.String suiteName, System.String pathName, System.String testName, MonoDevelop.NUnit.TestContext testContext) [0x0003e] in /usr/tmp/usr/ports/devel/monodevelop/work/monodevelop-4.0.9/src/addins/NUnit/Services/NUnitAssemblyTestSuite.cs:387 
  at MonoDevelop.NUnit.NUnitAssemblyTestSuite.OnRun (MonoDevelop.NUnit.TestContext testContext) [0x00001] in /usr/tmp/usr/ports/devel/monodevelop/work/monodevelop-4.0.9/src/addins/NUnit/Services/NUnitAssemblyTestSuite.cs:356 
  at MonoDevelop.NUnit.UnitTest.Run (MonoDevelop.NUnit.TestContext testContext) [0x0001e] in /usr/tmp/usr/ports/devel/monodevelop/work/monodevelop-4.0.9/src/addins/NUnit/Services/UnitTest.cs:361 </StackTrace>
    </UnitTestResult>
  </Results>
  <Tests />
</TestRecord>

Furthermore, attempt to run the tests manually leads to the following output:

$ nunit-console HelloTests.dll -xmlConsole
NUnit version 2.4.8
Copyright (C) 2002-2007 Charlie Poole.
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.

Runtime Environment - 
   OS Version: Unix 9.1.4.0
  CLR Version: 2.0.50727.1433 ( 3.1.2 (tarball Tue Jul 23 19:49:13 UTC 2013) )

Unhandled Exception:
System.ArgumentOutOfRangeException: Index is less than 0 or more than or equal to the list count.
Parameter name: index
0
  at System.Collections.ArrayList.ThrowNewArgumentOutOfRangeException (System.String name, System.Object actual, System.String message) [0x00000] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/class/corlib/System.Collections/ArrayList.cs:3244 
  at System.Collections.ArrayList.get_Item (Int32 index) [0x00013] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/class/corlib/System.Collections/ArrayList.cs:2635 
  at System.Diagnostics.ProcessModuleCollection.get_Item (Int32 index) [0x00000] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/class/System/System.Diagnostics/ProcessModuleCollection.cs:64 
  at System.Diagnostics.Process.get_MainModule () [0x00000] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/class/System/System.Diagnostics/Process.cs:228 
  at (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_MainModule ()
  at NUnit.Util.DomainManager.CreateDomain (NUnit.Core.TestPackage package) [0x0019f] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/nunit24/ClientUtilities/util/Services/DomainManager.cs:105 
  at NUnit.Util.TestDomain.Load (NUnit.Core.TestPackage package) [0x00011] in /usr/tmp/usr/ports/lang/mono/work/mono-3.1.2/mcs/nunit24/ClientUtilities/util/TestDomain.cs:52

Analysis:

System.Diagnostics.Process class implementation for Linux-based operating system uses procfs (/proc).
procfs is not enabled for FreeBSD by default.

Solution:

Mount procfs using /etc/fstab (reboot to apply):

proc /proc procfs rw 0 0

or mount procfs right now (without reboot):

mount -t procfs proc /proc

Since now MonoDevelop runs NUnit tests slightly!
Enjoy!

P.S. The same issue found here: FreeBSD, Mono y FireBird .Net Provider.