C# Moq

网友投稿 1439 2022-09-11

C# Moq

C# Moq

1 My Cases

1.1 简单入门

// 假定我有一个 MyFactory 用来创建 MyInterface 实例

// 创建 MyFactory 的 Mock 对象

var mockFactory = new Mock();

// 创建 MyInterface 的 Mock 实例

var mockInstance = new Mock();

// 使用 Moq 实现如果调用 MyInstance.DoSomething(bool) 方法无论传入参数为何值一概抛出 MyException 异常

mockInstance.Setup(c => c.DoSomething(It.IsAny()))

.Throws(new MyException("my exception message"));

// 使用 Moq 实现 MyFactory 的 Mock 实例第一次调用 CreateInstance(string) 方法时返回 MyInterface 的 Mock 实例

// 第二次及以后调用则返回真正的 MyInstance 实例

mockFactory.SetupSequence(f => f.CreateInstance(It.IsAny()))

.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

Methods Mock

using Moq;

// Assumptions:

public interface IFoo

{

Bar Bar { get; set; }

string Name { get; set; }

int Value { get; set; }

bool DoSomething(string value);

bool DoSomething(int number, string value);

string DoSomethingStringy(string value);

bool TryParse(string value, out string outputValue);

bool Submit(ref Bar bar);

int GetCount();

bool Add(int value);

}

public class Bar

{

public virtual Baz Baz { get; set; }

public virtual bool Submit() { return false; }

}

public class Baz

{

public virtual string Name { get; set; }

}

var mock = new Mock();

mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

// out arguments

var outString = "ack";

// TryParse will return true, and the out argument will return "ack", lazy evaluated

mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);

// ref arguments

var instance = new Bar();

// Only matches if the ref argument to the invocation is the same instance

mock.Setup(foo => foo.Submit(ref instance)).Returns(true);

// access invocation arguments when returning a value

mock.Setup(x => x.DoSomethingStringy(It.IsAny()))

.Returns((string s) => s.ToLower());

// Multiple parameters overloads available

// throwing when invoked with specific parameters

mock.Setup(foo => foo.DoSomething("reset")).Throws();

mock.Setup(foo => foo.DoSomething("")).Throws(new ArgumentException("command"));

// lazy evaluating return value

var count = 1;

mock.Setup(foo => foo.GetCount()).Returns(() => count);

// returning different values on each invocation

var mock = new Mock();

var calls = 0;

mock.Setup(foo => foo.GetCount())

.Returns(() => calls)

.Callback(() => calls++);

// returns 0 on first invocation, 1 on the next, and so on

Console.WriteLine(mock.Object.GetCount());

2.2 Matching Arguments

Arguments Mock

// any value

mock.Setup(foo => foo.DoSomething(It.IsAny())).Returns(true);

// any value passed in a `ref` parameter (requires Moq 4.8 or later):

mock.Setup(foo => foo.Submit(ref It.Ref.IsAny)).Returns(true);

// matching Func, lazy evaluated

mock.Setup(foo => foo.Add(It.Is(i => i % 2 == 0))).Returns(true);

// matching ranges

mock.Setup(foo => foo.Add(It.IsInRange(0, 10, Range.Inclusive))).Returns(true);

// matching regex

mock.Setup(x => x.DoSomethingStringy(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");

2.3 Properties

Common

Arguments Mock

mock.Setup(foo => foo.Name).Returns("bar");

// auto-mocking hierarchies (a.k.a. recursive mocks)

mock.Setup(foo => foo.Bar.Baz.Name).Returns("baz");

// expects an invocation to set the value to "foo"

mock.SetupSet(foo => foo.Name = "foo");

// or verify the setter directly

mock.VerifySet(foo => foo.Name = "foo");

Setup a property so that it will automatically start tracking its value (also known as Stub)

Arguments Mock

// start "tracking" sets/gets to this property

mock.SetupProperty(f => f.Name);

// alternatively, provide a default value for the stubbed property

mock.SetupProperty(f => f.Name, "foo");

// Now you can do:

IFoo foo = mock.Object;

// Initial value was stored

Assert.Equal("foo", foo.Name);

// New value set which changes the initial value

foo.Name = "bar";

Assert.Equal("bar", foo.Name);

Stub all properties on a mock (not available on Silverlight)

mock.SetupAllProperties();

2.4 Events

Events Mock

// Raising an event on the mock

mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue));

// Raising an event on the mock that has sender in handler parameters

mock.Raise(m => m.FooEvent += null, this, new FooEventArgs(fooValue));

// Raising an event on a descendant down the hierarchy

mock.Raise(m => m.Child.First.FooEvent += null, new FooEventArgs(fooValue));

// Causing an event to raise automatically when Submit is invoked

mock.Setup(foo => foo.Submit()).Raises(f => f.Sent += null, EventArgs.Empty);

// The raised event would trigger behavior on the object under test, which

// you would make assertions about later (how its state changed as a consequence, typically)

// Raising a custom event which does not adhere to the EventHandler pattern

public delegate void MyEventHandler(int i, bool b);

public interface IFoo

{

event MyEventHandler MyEvent;

}

var mock = new Mock();

...

// Raise passing the custom arguments expected by the event delegate

mock.Raise(foo => foo.MyEvent += null, 25, true);

2.5 Callbacks

Mock Callback

var mock = new Mock();

var calls = 0;

var callArgs = new List();

mock.Setup(foo => foo.DoSomething("ping"))

.Returns(true)

.Callback(() => calls++);

// access invocation arguments

mock.Setup(foo => foo.DoSomething(It.IsAny()))

.Returns(true)

.Callback((string s) => callArgs.Add(s));

// alternate equivalent generic method syntax

mock.Setup(foo => foo.DoSomething(It.IsAny()))

.Returns(true)

.Callback(s => callArgs.Add(s));

// access arguments for methods with multiple parameters

mock.Setup(foo => foo.DoSomething(It.IsAny(), It.IsAny()))

.Returns(true)

.Callback((i, s) => callArgs.Add(s));

// callbacks can be specified before and after invocation

mock.Setup(foo => foo.DoSomething("ping"))

.Callback(() => Console.WriteLine("Before returns"))

.Returns(true)

.Callback(() => Console.WriteLine("After returns"));

// callbacks for methods with `ref` / `out` parameters are possible but require some work (and Moq 4.8 or later):

delegate void SubmitCallback(ref Bar bar);

mock.Setup(foo => foo.Submit(ref It.Ref.IsAny)

.Callback(new SubmitCallback((ref Bar bar) => Console.WriteLine("Submitting a Bar!"));

2.6 Verification

Mock Verification

mock.Verify(foo => foo.DoSomething("ping"));

// Verify with custom error message for failure

mock.Verify(foo => foo.DoSomething("ping"), "When doing operation X, the service should be pinged always");

// Method should never be called

mock.Verify(foo => foo.DoSomething("ping"), Times.Never());

// Called at least once

mock.Verify(foo => foo.DoSomething("ping"), Times.AtLeastOnce());

// Verify getter invocation, regardless of value.

mock.VerifyGet(foo => foo.Name);

// Verify setter invocation, regardless of value.

mock.VerifySet(foo => foo.Name);

// Verify setter called with specific value

mock.VerifySet(foo => foo.Name ="foo");

// Verify setter with an argument matcher

mock.VerifySet(foo => foo.Value = It.IsInRange(1, 5, Range.Inclusive));

// Verify that no other invocations were made other than those already verified (requires Moq 4.8 or later)

mock.VerifyNoOtherCalls();

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(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 { 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 { 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();

// Create a mock overriding the repository settings

var barMock = repository.Create(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();

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();

mock.Protected()

.Setup("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("Execute",

ItExpr.IsAny())

.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()

.Setup(m => m.Execute(It.IsAny())) // 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();

var disposableFoo = mock.As();

// now the IFoo mock also implements IDisposable :)

disposableFoo.Setup(disposable => disposable.Dispose());

// implementing multiple interfaces in single mock

var mock = new Mock();

mock.Setup(foo => foo.Name).Returns("Fred");

mock.As().Setup(disposable => disposable.

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:搞了个免驱的摄像头,写了个程序来测试一下。
下一篇:Windows之子系统WSL
相关文章

 发表评论

暂时没有评论,来抢沙发吧~