フェイクにモックを加えるクラス
これを毎回実装する手間を省くために、RealProxy 使って WrappingMock なんてクラスを作ってみた。
using System; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Proxies; using NUnit.Mocks; public sealed class WrappingMock<T> : Mock { public WrappingMock(T rawInstance) { if (rawInstance == null) { throw new ArgumentNullException("rawInstance"); } this._mockProxy = new MockProxy(rawInstance, this); } private readonly MockProxy _mockProxy; public T MockInstance { get { return this._mockProxy.GetTransparentProxy(); } } private sealed class MockProxy : RealProxy { private readonly T _targetInstance; private readonly ICallHandler _callHandler; public T TargetInstance { get { return this._targetInstance; } } public MockProxy(T targetInstance, ICallHandler callHandler) : base(typeof(T)) { this._targetInstance = targetInstance; this._callHandler = callHandler; } public override IMessage Invoke(IMessage msg) { IMethodCallMessage methodCallMessage = (IMethodCallMessage)msg; MethodBase targetMethod = methodCallMessage.MethodBase; object[] args = methodCallMessage.Args; ReturnMessage returnMessage; try { object result = this._callHandler.Call(targetMethod.Name, args) ?? targetMethod.Invoke(this.TargetInstance, args); returnMessage = new ReturnMessage(result, args, args.Length, methodCallMessage.LogicalCallContext, methodCallMessage); } catch (Exception ex) { ex = (ex is TargetInvocationException) ? ex.InnerException : ex; returnMessage = new ReturnMessage(ex, methodCallMessage); } return returnMessage; } public new T GetTransparentProxy() { return (T)base.GetTransparentProxy(); } } }
前回と同じく、こんな IHoge インターフェイスがあって
public interface IHoge { bool Piyo(); }
前回と同じく、こんな Fuga クラスが使用するとする。
public class Fuga { private IHoge _hoge; public Fuga(IHoge hoge) { this._hoge = hoge; } public bool HogePiyo() { return this._hoge.Piyo(); } }
今回はフェイクを単純に実装できる。
public class HogeFake : IHoge { public bool Piyo() { return true; } }
で、こんな風に使用できる。
[TestFixture] public class TestFixture1 { [Test] public void Test1() { WrappingMock<IHoge> hogeMockery = new WrappingMock<IHoge>(new HogeFake()); hogeMockery.Strict = true; hogeMockery.Expect("Piyo"); IHoge hogeMock = hogeMockery.MockInstance; Fuga f = new Fuga(hogeMock); bool b = f.HogePiyo(); Assert.That(b, Is.True); hogeMockery.Verify(); } [Test] public void Test2() { WrappingMock<IHoge> hogeMockery = new WrappingMock<IHoge>(new HogeFake()); hogeMockery.Strict = true; hogeMockery.ExpectAndReturn("Piyo", false); IHoge hogeMock = hogeMockery.MockInstance; Fuga f = new Fuga(hogeMock); bool b = f.HogePiyo(); Assert.That(b, Is.False); hogeMockery.Verify(); } [Test] [ExpectedException(typeof(InvalidOperationException))] public void Test3() { WrappingMock<IHoge> hogeMockery = new WrappingMock<IHoge>(new HogeFake()); hogeMockery.Strict = true; hogeMockery.ExpectAndThrow("Piyo", new InvalidOperationException()); IHoge hogeMock = hogeMockery.MockInstance; Fuga f = new Fuga(hogeMock); f.HogePiyo(); } }
見ての通り、DynamicMock と似たような使い方ができる。