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

时间:2017-04-10 09:55:49

标签: c# unit-testing reflection moq

我的方法有一个类型参数,所以我在我的单元测试中尝试定义一个模拟对象并传递一个希望的类型,这种类型的实例将模拟我已经定义它的方法。但是如果我在用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...
    }
}

2 个答案:

答案 0 :(得分:0)

当我阅读您的代码时,我假设您要测试IAmAnInterface界面。但是,您只能测试作为接口实现的类,因为它包含描述您的方法应该执行的操作的代码。

我建议您从头开始编写测试时考虑以下因素:当您在类或您正在测试的方法中使用mocking时,请使用mocking。因为可能很难操纵依赖类,例如返回错误,所以模拟这些将使您更容易测试方法中可能出现的各种情况。

我希望下面的例子会更清楚。

假设我们有两个类,每个类都有自己的接口:

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";
    }
}

我希望在课程DoFuncX中测试Foo,并且当catch引发错误时,我希望它会在_bar.DoFunctY中输入:

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

代码可能包含错误,但我认为它可以明确它应该做什么。

答案 1 :(得分:0)

您需要摆脱Whole Module的电话。显而易见,要做的是让post_install do |installer| installer.pods_project.targets.each do |target| # Cache pod does not accept optimization level '-O', causing Bus 10 error. Use '-Osize' or '-Onone' if target.name == 'Cache' target.build_configurations.each do |config| level = '-Osize' config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = level puts "Set #{target.name} #{config.name} to Optimization Level #{level}" end end end end 传递给工厂方法,或者/以及传递CreateInstance(如果不能传递实例以直接使用):

DoFunc

当然,您可以安排通过其他方式提供工厂,或通过依赖项注入系统注入实例。

这可能意味着必须更改任何包含Type的方式。

例如您可以改为将工厂传递给实现void DoFunc(Func<IAmAnInterface<MyViewModel>> factory) { var vmod = new MyViewModel(); var objImplInterface = factory(); objImplInterface.DoInterfaceFunc(vmod); if (vmod.Created) { //more logic... } } 的构造函数,然后在DoFunc中使用它,并且在测试过程中当然要提供一个模拟,以将模拟的接口交出。