Moq
1 My Cases
1.1 简单入门
2 Reference
2.1 Methods
2.2 Matching Arguments
2.3 Properties
2.4 Events
2.5 Callbacks
2.6 Verification
2.7 Customizing Mock Behavior
2.8 Miscellaneous
2.9 Advanced Features
2.10 LINQ to Mocks
3 FAQ
3.1 static class/method
1 My Cases
1.1 简单入门
// 假定我有一个 MyFactory 用来创建 MyInterface 实例 // 创建 MyFactory 的 Mock 对象 var mockFactory = new Mock<MyFactory>(); // 创建 MyInterface 的 Mock 实例 var mockInstance = new Mock<MyInterface>(); // 使用 Moq 实现如果调用 MyInstance.DoSomething(bool) 方法无论传入参数为何值一概抛出 MyException 异常 mockInstance.Setup(c => c.DoSomething(It.IsAny<bool>())) .Throws(new MyException("my exception message")); // 使用 Moq 实现 MyFactory 的 Mock 实例第一次调用 CreateInstance(string) 方法时返回 MyInterface 的 Mock 实例 // 第二次及以后调用则返回真正的 MyInstance 实例 mockFactory.SetupSequence(f => f.CreateInstance(It.IsAny<string>())) .Returns(mockInstance.Object) .Returns(new MyInstance("real object")); client.Factory = mockFactory.Object;
2 Reference
Please refer to Moq Quickstart
Moq is intended to be simple to use, strongly typed (no magic strings!, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional!).
2.1 Methods
2.2 Matching Arguments
2.3 Properties
-
Common
-
Setup a property so that it will automatically start tracking its value (also known as Stub)
-
Stub all properties on a mock (not available on Silverlight)
mock.SetupAllProperties();
2.4 Events
2.5 Callbacks
2.6 Verification
2.7 Customizing Mock Behavior
-
Make mock behave like a "true Mock", raising exceptions for anything that doesn't have a corresponding expectation: in Moq slang a "Strict" mock; default behavior is "Loose" mock, which never throws and returns default values or empty arrays, enumerables, etc. if no expectation is set for a member
var mock = new Mock<IFoo>(MockBehavior.Strict);
-
Invoke base class implementation if no expectation overrides the member (a.k.a. "Partial Mocks" in Rhino Mocks): default is false. (this is required if you are mocking Web/Html controls in System.Web!)
var mock = new Mock<IFoo> { CallBase = true };
-
Make an automatic recursive mock: a mock that will return a new mock for every member that doesn't have an expectation and whose return value can be mocked (i.e. it is not a value type)
var mock = new Mock<IFoo> { DefaultValue = DefaultValue.Mock }; // default is DefaultValue.Empty // this property access would return a new mock of Bar as it's "mock-able" Bar value = mock.Object.Bar; // the returned mock is reused, so further accesses to the property return // the same mock instance. this allows us to also use this instance to // set further expectations on it if we want var barMock = Mock.Get(value); barMock.Setup(b => b.Submit()).Returns(true);
-
Centralizing mock instance creation and management: you can create and verify all mocks in a single place by using a MockRepository, which allows setting the MockBehavior, its CallBase and DefaultValue consistently
var repository = new MockRepository(MockBehavior.Strict) { DefaultValue = DefaultValue.Mock }; // Create a mock using the repository settings var fooMock = repository.Create<IFoo>(); // Create a mock overriding the repository settings var barMock = repository.Create<Bar>(MockBehavior.Loose); // Verify all verifiable expectations on all mocks created through the repository repository.Verify();
2.8 Miscellaneous
-
Setting up a member to return different values / throw exceptions on sequential calls:
var mock = new Mock<IFoo>(); mock.SetupSequence(f => f.GetCount()) .Returns(3) // will be returned on 1st invocation .Returns(2) // will be returned on 2nd invocation .Returns(1) // will be returned on 3rd invocation .Returns(0) // will be returned on 4th invocation .Throws(new InvalidOperationException()); // will be thrown on 5th invocation
-
Setting expectations for protected members (you can't get IntelliSense for these, so you access them using the member name as a string):
// at the top of the test fixture using Moq.Protected; // in the test var mock = new Mock<CommandBase>(); mock.Protected() .Setup<int>("Execute") .Returns(5); // if you need argument matching, you MUST use ItExpr rather than It // planning on improving this for vNext (see below for an alternative in Moq 4.8) mock.Protected() .Setup<bool>("Execute", ItExpr.IsAny<string>()) .Returns(true);
-
Moq 4.8 and later allows you to set up protected members through a completely unrelated type that has the same members and thus provides the type information necessary for IntelliSense to work. You can also use this interface to set up protected generic methods and those having by-ref parameters:
interface CommandBaseProtectedMembers { bool Execute(string arg); } mock.Protected().As<CommandBaseProtectedMembers>() .Setup(m => m.Execute(It.IsAny<string>())) // will set up CommandBase.Execute .Returns(true);
2.9 Advanced Features
-
Common
// get mock from a mocked instance IFoo foo = // get mock instance somehow var fooMock = Mock.Get(foo); fooMock.Setup(f => f.GetCount()).Returns(42); // implementing multiple interfaces in mock var mock = new Mock<IFoo>(); var disposableFoo = mock.As<IDisposable>(); // now the IFoo mock also implements IDisposable :) disposableFoo.Setup(disposable => disposable.Dispose()); // implementing multiple interfaces in single mock var mock = new Mock<IFoo>(); mock.Setup(foo => foo.Name).Returns("Fred"); mock.As<IDisposable>().Setup(disposable => disposable.Dispose()); // custom matchers mock.Setup(foo => foo.DoSomething(IsLarge())).Throws<ArgumentException>(); ... public string IsLarge() { return Match.Create<string>(s => !String.IsNullOrEmpty(s) && s.Length > 100); }
-
Mocking internal types: Add either of the following custom attributes (typically in AssemblyInfo.cs) to the project containing the internal types — which one you need depends on whether your own project is strong-named or not:
// This assembly is the default dynamic assembly generated by Castle DynamicProxy, // used by Moq. If your assembly is strong-named, paste the following in a single line: [assembly:InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=00...cc7")] // Or, if your own assembly is not strong-named, omit the public key: [assembly:InternalsVisibleTo("DynamicProxyGenAssembly2")]
-
Starting in Moq 4.8, you can create your own custom default value generation strategies (besides DefaultValue.Empty and DefaultValue.Mock) by subclassing DefaultValueProvider, or, if you want some more convenience, LookupOrFallbackDefaultValueProvider:
class MyEmptyDefaultValueProvider : LookupOrFallbackDefaultValueProvider { public MyEmptyDefaultValueProvider() { base.Register(typeof(string), (type, mock) => "?"); base.Register(typeof(List<>), (type, mock) => Activator.CreateInstance(type)); } } var mock = new Mock<IFoo> { DefaultValueProvider = new MyEmptyDefaultValueProvider() }; var name = mock.Object.Name; // => "?"
2.10 LINQ to Mocks
Moq is the one and only mocking framework that allows specifying mock behavior via declarative specification queries. You can think of LINQ to Mocks as:
Keep that query form in mind when reading the specifications:
var services = Mock.Of<IServiceProvider>(sp => sp.GetService(typeof(IRepository)) == Mock.Of<IRepository>(r => r.IsAuthenticated == true) && sp.GetService(typeof(IAuthentication)) == Mock.Of<IAuthentication>(a => a.AuthenticationType == "OAuth")); // Multiple setups on a single mock and its recursive mocks ControllerContext context = Mock.Of<ControllerContext>(ctx => ctx.HttpContext.User.Identity.Name == "kzu" && ctx.HttpContext.Request.IsAuthenticated == true && ctx.HttpContext.Request.Url == new Uri("http://moqthis.com") && ctx.HttpContext.Response.ContentType == "application/xml"); // Setting up multiple chained mocks: var context = Mock.Of<ControllerContext>(ctx => ctx.HttpContext.Request.Url == new Uri("http://moqthis.me") && ctx.HttpContext.Response.ContentType == "application/xml" && // Chained mock specification ctx.HttpContext.GetSection("server") == Mock.Of<ServerSection>(config => config.Server.ServerUrl == new Uri("http://moqthis.com/api"));
LINQ to Mocks is great for quickly stubbing out dependencies that typically don't need further verification. If you do need to verify later some invocation on those mocks, you can easily retrieve them with Mock.Get(instance).
3 FAQ
3.1 static class/method
Moq 不支持对静态类或方法的 mock. 作为变通,可以使用实例方法来调用静态方法,再去 mock 实例方法。