繁体   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