当前位置: 首页 > 工具软件 > moq > 使用案例 >

Moq快速开始翻译

袁轶
2023-12-01

Moq Quickstart


内容来自MoqWiki: Moq4 Quickstart

方法

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);
    Task<bool> DoSomethingAsync();
    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<IFoo>();
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
// TryParse方法被调用后将延迟计算返回 true ,out 参数将会被赋值为 "ack" 并返回
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<string>()))
		.Returns((string s) => s.ToLower());
// Multiple parameters overloads available
// 使用多个参数的重载

// throwing when invoked with specific parameters
// 当调用指定参数时抛出异常
mock.Setup(foo => foo.DoSomething("reset")).Throws<InvalidOperationException>();
mock.Setup(foo => foo.DoSomething("")).Throws(new ArgumentException("command"));

// lazy evaluating return value
// 延迟计算需要返回的值
var count = 1;
mock.Setup(foo => foo.GetCount()).Returns(() => count);

// async methods (see below for more about async):
// 异步方法(在下面查看更多关于异步):
mock.Setup(foo => foo.DoSomethingAsync().Result).Returns(true);

异步方法

这有几个设置异步方法的方式(例如:一个方法返回一个Task或ValueTask):

  • 从 Moq4.16 开始,你可以简单的返回任务的属性。这在几乎所有的Setup和Verification表达式中都有效:
    mock.Setup(foo => foo.DoSomethingAsync().Result).Returns(true);
    
  • 在最近的版本中,使用setup帮助方法类似 setup.ReturnsAsync,setup.ThrowAsync这两个都可以:
    mock.Setup(foo => foo.DoSomethingAsync()).ReturnAsync(true);
    
  • 你也可以像下面这样的做法,但是这样会触发一个关于异步lambda同步执行的编译警告:
    mock.Setup(foo => foo.DoSomethingAsync()).Returns(async () => 42);
    

匹配参数

// any value
mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(true);

// any value passed in a `ref` parameter (requires Moq 4.8 or later):
// 任何通过引用参数传递的值(必须在 Moq4.8 及以上版本):
mock.Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny)).Returns(true);

// mathcing Func<int>,lazy evaluated
// 配置Func<int>类型的委托,并延迟计算返回
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0 ))).Returns(true);

// matching reanges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0,10,Range.Inclusive))).Returns(true);

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

属性

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"
// 值可以预期的将会设置为"foo"
mock.SetupSet(foo => foo.Name = "foo");

//or verify the setter directly
// 或直接验证设置器
mock.VerifySet(foo => foo.Name = "foo");
  • 设置属性,使其自动开始跟踪其值(也称为存根):
// start "tracking"  sets/gets to this property
// 开始 跟踪 这个属性的gets和sets
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 changed the initial value
// 新值集可更改初始值
foo.Name = "bar";
Assert.Equal("bar", foo.Name);
  • 将所有属性存入模拟
mock.SetupAllProperties();

事件模拟

// Setting up an event's `add` and `remove` accessors (requires Moq 4.13 or later):
// 设置一个事件的添加和移除访问器(Moq的版本必须是4.13及以上):
mock.SetupAdd(m => m.FooEvent += It.IsAny<EventHandler>())...;
mock.SetupRemove(m => m.FooEvent -= It.IsAny<EventHandler>())...;

// Raising an event on the mock
// 在模拟时新增一个事件
mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue));

//Raising an event on the mock that has sender inhadnler 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
// 调用Submit时导致事件自动触发
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 whick does not adhere to the EventHandler pattern
// 引发自定义事件提示不符合EventHandler模​​式
public delegate void MyEventHandler(int i,bool b);
public interface IFoo
{event MyEventHandler MyEvent;}
var mock = new Mock<IFoo>();

// Raise passing the custom arguments expected by the event delegate
// 提高传递事件委托期望的自定义​​参数
mock.Raise(foo => foo.MyEvent +=null,25,true);

回调

var mock = new Mock<IFoo>();
var calls = 0;
var callArgs = new List<string>();

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

// access invocation arguments
mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
    .Callback((string s) => callArgs.Add(s)).Returns(true);

// alternate equivalent generic method syntax
// 替代等效泛型方法语法
mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
    .Callback<string

mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Callback<int,string>((i,s) => callArgs.Add(s)).Returns(true);


 类似资料: