簡體   English   中英

是否可以使用Activator.CreateInstance()模擬方法?

[英]Is it possible to mock a method with using of Activator.CreateInstance()?

我的方法有一個類型參數,因此我在單元測試中嘗試定義一個模擬對象並傳遞其類型,希望這種類型的實例可以像我定義的那樣模擬該方法。 但是,如果使用Activator.CreateInstance()創建模擬的方法后調用它的方法,則將成為NotImplementedException。

是否可以使用Activator.CreateInstance()模擬方法?

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
public class MyTestClass
{
    [TestMethod]
    public void TestDoFunc()
    {
        var vmod = new MyViewModel();
        var mock = new Mock<IAmAnInterface<MyViewModel>>();
        mock.Setup(x => x.DoInterfaceFunc(vmod)).Callback<MyViewModel>((viewModel) => { viewModel.Created = true; }).Returns(true);
        Assert.IsTrue(mock.Object.DoInterfaceFunc<MyViewModel>(vmod));//this works
        Assert.IsTrue(vmod.Created);//this works

        var mockObjFromActivator = Activator.CreateInstance(mock.Object.GetType()) as IAmAnInterface<MyViewModel>;
        Assert.IsTrue(mockObjFromActivator.DoInterfaceFunc<MyViewModel>(vmod));//this throw NotImplementedException
    }
}
public class MyViewModel { public bool Created { get; set; } }
public interface IAmAnInterface<TViewModel> { bool DoInterfaceFunc<TViewModel>(TViewModel vmod); }

編輯:

我想測試這樣的功能:

void DoFunc(Type objType)
{
    var vmod = new MyViewModel();
    var objImplInterface = Activator.CreateInstance(objType) as IAmAnInterface<MyViewModel>;
    objImplInterface.DoInterfaceFunc(vmod);
    if (vmod.Created)
    {
        //more logic...
    }
}

當我閱讀您的代碼時,我假設您想測試IAmAnInterface接口。 但是,您只能測試作為接口實現的類,因為它包含描述您的方法應該執行的代碼。

我建議您從頭開始編寫測試,並牢記以下幾點:當模擬是您要測試的類或方法中的依賴項時,請使用模擬。 因為可能很難操縱依賴類,例如返回錯誤,所以對它們進行模擬將使測試方法中可能發生的各種情況變得更加容易。

我希望下面的例子可以使它更加清楚。

假設我們有2個類,每個類都有自己的接口:

public interface IFoo {
    string DoFuncX();
}

public class Foo : IFoo
{
    IBar _bar;

    public Foo(IBar bar) {
        _bar = bar;
    }

    public string DoFuncX() {
        try {
            return _bar.DoFuncY();
        } catch (Exception ex) {
            return "ERROR";
        }
    }
}

public interface IBar {
    string DoFuncY();
}

public class Bar : IBar {
    public string DoFuncY() {
        return "bar";
    }
}

我想在Foo類中測試DoFuncX ,並且我希望它在_bar.DoFunctY引發錯誤時進入catch

Test__Foo_DoFuncX__IBar_Throws_Error() {

    // Arrange
    var mockedIBar = Mock<IBar>();
    mockedIBar.Setup(b => b.DoFuncY()).throw(new Exception("Mocked IBar Throws Errors"));

    // Act
    var foo = new Foo(mockedIBar);
    var result = foo.DoFuncX();

    // Assert
    Assert.Equal(result, "ERROR");
}

代碼可以包含錯誤,但是我認為它可以清楚地說明應該做什么。

您需要擺脫CreateInstance調用。 顯而易見的事情是讓DoFunc傳遞給工廠方法代替,或者傳遞給Type (以及Type (如果不能傳遞給實例直接使用):

void DoFunc(Func<IAmAnInterface<MyViewModel>> factory)
{
    var vmod = new MyViewModel();
    var objImplInterface = factory();
    objImplInterface.DoInterfaceFunc(vmod);
    if (vmod.Created)
    {
        //more logic...
    }
}

當然,您也許可以安排通過其他方式為工廠提供服務,或者通過依賴項注入系統來注入實例。

不管如何包含這可能意味着改變,反過來,對於DoFunc必須創建。

例如,您可能改為將工廠傳遞給實現Func<Type, IAmAnInterface<MyViewModel>的構造函數,然后再在DoFunc使用它,並且在測試過程中當然要提供一個模擬,以將模擬接口DoFunc

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM