Welcome to RightHand's community place Sign in | | Help

Creating wrappers for sealed and other types for mocking

Did you ever wanted to mock a sealed class or non-virtual methods? Unless you are using TypeMock you are in for some coding as there is no easy way to mock them just like that (I am fiddling with MOQ but AFAIK no mock framework is capable of mocking sealed classes with exception of TypeMock). The general pattern I see is to create a wrapper class that implements an interface (you have to create that interface, too, most of the times). Let's see an example with a class Tubo:

public class Tubo { public void SomeMethod() { } public int SomeProperty { get { return 1; } }

To be able to mock this class you have to create ITubo interface and a TuboWrapper class like this:

public interface ITubo { void SomeMethod(); int SomeProperty { get; } } public class TuboWrapper: ITubo { private Tubo tubo = new Tubo(); public void SomeMethod() { tubo.SomeMethod(); } public int SomeProperty { get { return tubo.SomeProperty; } } }

It sounds like highly boring and time consuming exercise, doesn't it. Specially if you have to wrap a class rich with methods and properties. One could argue that you should think before creating non-mockable types. True, but one can't help when dealing with non-user types (i.e. .net framework types).

One solution would be to go duck typing as Phil Haack explains. There is also a library that enabled such typing. However, there are two arguments against duck typing:

  • slight performance hit
  • you still have to code the interface

So, it goes half way to solve the problem.

That's why I've created a CodeSmith template that generates both wrapper and interface for you out of a type in an assembly. Note that this is a very raw version that would work with types located in System and System.Core assemblies (and perhaps others that are linked to the template) as I really don't have too much time right now. I might enhance it in the future.

Here is a sample configuration for creating ReaderWriterLockSlim wrapper:

<?xml version="1.0"?> <codeSmith xmlns="http://www.codesmithtools.com/schema/csp.xsd"> <propertySets> <propertySet output="WrapperGenerator.cs" template="..\CodeSmith Templates\WrapperGenerator.cst"> <property name="Postfix">Wrapper</property> <property name="InternalQualifier">private</property> <property name="IgnoreObjectMethodsAndProperties">True</property> <property name="Types"> <stringList> <string>System.Threading.ReaderWriterLockSlim</string> </stringList> </property> <property name="Namespace">Namespace.Wrappers</property> </propertySet> </propertySets> </codeSmith>

and here is autogenerated code:

namespace Namespace.Wrappers { using System; #region ReaderWriterLockSlim wrapper public interface IReaderWriterLockSlim { #region Properties bool IsReadLockHeld { get; } bool IsUpgradeableReadLockHeld { get; } bool IsWriteLockHeld { get; } System.Threading.LockRecursionPolicy RecursionPolicy { get; } int CurrentReadCount { get; } int RecursiveReadCount { get; } int RecursiveUpgradeCount { get; } int RecursiveWriteCount { get; } int WaitingReadCount { get; } int WaitingUpgradeCount { get; } int WaitingWriteCount { get; } #endregion #region Methods void EnterReadLock (); bool TryEnterReadLock (TimeSpan timeout); bool TryEnterReadLock (int millisecondsTimeout); void EnterWriteLock (); bool TryEnterWriteLock (TimeSpan timeout); bool TryEnterWriteLock (int millisecondsTimeout); void EnterUpgradeableReadLock (); bool TryEnterUpgradeableReadLock (TimeSpan timeout); bool TryEnterUpgradeableReadLock (int millisecondsTimeout); void ExitReadLock (); void ExitWriteLock (); void ExitUpgradeableReadLock (); void Dispose (); #endregion } public partial class ReaderWriterLockSlimWrapper: IReaderWriterLockSlim { private System.Threading.ReaderWriterLockSlim core; public ReaderWriterLockSlimWrapper() { this.core = new System.Threading.ReaderWriterLockSlim(); } public ReaderWriterLockSlimWrapper(System.Threading.ReaderWriterLockSlim core) { this.core = core; } #region Properties public bool IsReadLockHeld { get { return core.IsReadLockHeld; } } public bool IsUpgradeableReadLockHeld { get { return core.IsUpgradeableReadLockHeld; } } public bool IsWriteLockHeld { get { return core.IsWriteLockHeld; } } public System.Threading.LockRecursionPolicy RecursionPolicy { get { return core.RecursionPolicy; } } public int CurrentReadCount { get { return core.CurrentReadCount; } } public int RecursiveReadCount { get { return core.RecursiveReadCount; } } public int RecursiveUpgradeCount { get { return core.RecursiveUpgradeCount; } } public int RecursiveWriteCount { get { return core.RecursiveWriteCount; } } public int WaitingReadCount { get { return core.WaitingReadCount; } } public int WaitingUpgradeCount { get { return core.WaitingUpgradeCount; } } public int WaitingWriteCount { get { return core.WaitingWriteCount; } } #endregion #region Methods public void EnterReadLock() { core.EnterReadLock(); } public bool TryEnterReadLock(TimeSpan timeout) { return core.TryEnterReadLock(timeout); } public bool TryEnterReadLock(int millisecondsTimeout) { return core.TryEnterReadLock(millisecondsTimeout); } public void EnterWriteLock() { core.EnterWriteLock(); } public bool TryEnterWriteLock(TimeSpan timeout) { return core.TryEnterWriteLock(timeout); } public bool TryEnterWriteLock(int millisecondsTimeout) { return core.TryEnterWriteLock(millisecondsTimeout); } public void EnterUpgradeableReadLock() { core.EnterUpgradeableReadLock(); } public bool TryEnterUpgradeableReadLock(TimeSpan timeout) { return core.TryEnterUpgradeableReadLock(timeout); } public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) { return core.TryEnterUpgradeableReadLock(millisecondsTimeout); } public void ExitReadLock() { core.ExitReadLock(); } public void ExitWriteLock() { core.ExitWriteLock(); } public void ExitUpgradeableReadLock() { core.ExitUpgradeableReadLock(); } public void Dispose() { core.Dispose(); } #endregion } #endregion }

Do you still want to code them by hand? Or do you want to use this template? Rhetoric question? What do you think?

Anyway, go get the template here.

Published 22. julij 2008 17:23 by Miha Markic
Filed under: ,

Comments

Anonymous comments are disabled