C# Moq

来源:https://www.cnblogs.com/lldwolf/archive/2019/11/07/10947060.html
-Advertisement-
Play Games

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 B ...


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

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


// returning different values on each invocation
var mock = new Mock<IFoo>();
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<string>())).Returns(true);


// any value passed in a `ref` parameter (requires Moq 4.8 or later):
mock.Setup(foo => foo.Submit(ref It.Ref<Bar>.IsAny)).Returns(true);


// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true); 


// matching ranges
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");

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<IFoo>();
...
// 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<IFoo>();
var calls = 0;
var callArgs = new List<string>();

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

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

// alternate equivalent generic method syntax
mock.Setup(foo => foo.DoSomething(It.IsAny<string>()))
    .Returns(true)
    .Callback<string>(s => callArgs.Add(s));

// access arguments for methods with multiple parameters
mock.Setup(foo => foo.DoSomething(It.IsAny<int>(), It.IsAny<string>()))
    .Returns(true)
    .Callback<int, string>((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<Bar>.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<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;  // => "?"
    

    Note: When you pass the mock for consumption, you must pass mock.Object, not mock itself.

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 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近,決定在一個項目用tp5進行APP介面開發,用Python做數據分析,然後這就面臨一個問題:PHP和Python如何進行數據交互? 思路 我解決此問題的方法是利用了PHP的passthru函數來調用命令運行Python腳本。 實現 在PHP中調用命令運行Python腳本 1 2 3 4 5 6 ...
  • 在實際開發中,有時候為了及時處理請求和進行響應,我們可能會多任務同時執行,或者先處理主任務,也就是非同步調用,非同步調用的實現有很多,例如多線程、定時任務、消息隊列等, 這一章節,我們就來講講@Async非同步方法調用。 一、@Async使用演示 @Async是Spring內置註解,用來處理非同步任務,在S ...
  • 如何提高效率問題,往往同樣的功能,不一樣的代碼,出來的效率往往大不一樣。 ● 用單引號代替雙引號來包含字元串,這樣做會更快一些。因為PHP會在雙引號包圍的字元串中搜尋變數,單引號則不會,註意:只有echo能這麼做,它 是一種可以把多個字元串當作參數的“函數”(譯註:PHP手冊中說echo是語言結構, ...
  • php數組中有一些函數與數學相關的函數,大多都是以array開頭然後下劃線接一個數學上的英文單詞,如下: 1 array_diff() 2 array_diff_assoc() 3 array_intersect() 4 array_intersect_assoc() 5 array_sum() 6 ...
  • 依賴註入 當A類需要依賴於B類,也就是說需要在A類中實例化B類的對象來使用時候,如果B類中的功能發生改變,也會導致A類中使用B類的地方也要跟著修改,導致A類與B類高耦合。這個時候解決方式是,A類應該去依賴B類的介面,把具體的類的實例化交給外部。 就拿我們業務中常用的通知模塊來說。 1 2 3 4 5 ...
  • 1. 基礎數據類型補充 li = ["李嘉誠", "麻花藤", "⻩海峰", "劉嘉玲"] s = "_".join(li) print(s) li = "⻩花⼤閨⼥" s = "_".join(li) print(s) 列表: 迴圈刪除列表中的每⼀個元素 li = [11, 22, 33, 44] ...
  • Platform.runLater一些情況下沒有賦值到fx頁面上 採用task方式 ...
  • 以前寫過ASP.NET Core 2.x的REST API文章,今年再更新一下到3.0版本。 預備知識:ASP.NET Core 和 C# 以前寫過ASP.NET Core 2.x的REST API文章,今年再更新一下到3.0版本。 預備知識:ASP.NET Core 和 C# 工具:Visual ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...