简体   繁体   English

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

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

My method has a type parameter, so I am trying in my unit test to define a mock object and pass a type of it with a hope, that the instance of this type will mock the method as I have defined it. 我的方法有一个类型参数,因此我在单元测试中尝试定义一个模拟对象并传递其类型,希望这种类型的实例可以像我定义的那样模拟该方法。 But if I call a method of my mock after I have created it with Activator.CreateInstance(), I become NotImplementedException. 但是,如果使用Activator.CreateInstance()创建模拟的方法后调用它的方法,则将成为NotImplementedException。

Is it possible to mock a method with using of Activator.CreateInstance()? 是否可以使用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); }

EDIT: 编辑:

I want to test such function: 我想测试这样的功能:

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

When I read your code I assume you want to test your IAmAnInterface interface. 当我阅读您的代码时,我假设您想测试IAmAnInterface接口。 However you can only test a class which is an implementation of the interface because it contains code which describes what your method should do. 但是,您只能测试作为接口实现的类,因为它包含描述您的方法应该执行的代码。

I would recommend your to write your test from scratch with the following in mind: use mocking when their are dependencies in your class or method which you are testing. 我建议您从头开始编写测试,并牢记以下几点:当模拟是您要测试的类或方法中的依赖项时,请使用模拟。 Because it could be hard to manipulate the depended class for example to return an error, mocking those will make it easier to test various situations which can occur in your method. 因为可能很难操纵依赖类,例如返回错误,所以对它们进行模拟将使测试方法中可能发生的各种情况变得更加容易。

I hope the example below would make it more clear. 我希望下面的例子可以使它更加清楚。

Let say we have 2 classes with each their own interface: 假设我们有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";
    }
}

and I want to test DoFuncX in class Foo and I expect that it enters in catch when _bar.DoFunctY throws an error: 我想在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");
}

code can contains errors, but I think it makes clear what it should do. 代码可以包含错误,但是我认为它可以清楚地说明应该做什么。

You need to get rid of the CreateInstance call. 您需要摆脱CreateInstance调用。 The obvious thing to do is to have DoFunc be passed a factory method instead or/as well as the Type (if it can't be passed the instance to use directly): 显而易见的事情是让DoFunc传递给工厂方法代替,或者传递给Type (以及Type (如果不能传递给实例直接使用):

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

Of course, you may be able to arrange for the factory to be supplied via other means, or for the instance to use to be injected by a dependency injection system. 当然,您也许可以安排通过其他方式为工厂提供服务,或者通过依赖项注入系统来注入实例。

This may mean changes, in turn, for how whatever contains DoFunc has to be created. 不管如何包含这可能意味着改变,反过来,对于DoFunc必须创建。

Eg you may instead have a factory passed to the constructor that implements Func<Type, IAmAnInterface<MyViewModel> and you then later use that in DoFunc , and of course provide a mock during testing that hands back the mocked interface. 例如,您可能改为将工厂传递给实现Func<Type, IAmAnInterface<MyViewModel>的构造函数,然后再在DoFunc使用它,并且在测试过程中当然要提供一个模拟,以将模拟接口DoFunc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 模拟静态方法Activator.CreateInstance以返回另一个类的模拟 - Mock static method Activator.CreateInstance to return a mock of another class 结合使用Activator.CreateInstance()和属性 - Using Activator.CreateInstance() with properties 是否可以使用Activator.CreateInstance()使用参数构造函数创建泛型工厂? - Is it possible to create a generic factory with constructor with parameters using Activator.CreateInstance()? 在泛型类中使用Activator.CreateInstance结合方法上的“ new”修饰符 - Using Activator.CreateInstance in generic class combined with “new” modifier on method 如何测试使用Activator.CreateInstance(…)的方法? - How to test a method that uses Activator.CreateInstance(…)? 创建一个方法的DeclaringType实例:Activator.CreateInstance - Create an instance of the DeclaringType of a method: Activator.CreateInstance 使用FastActivator代替Activator.CreateInstance() - Using FastActivator in place of Activator.CreateInstance() C#使用Activator.CreateInstance - C# Using Activator.CreateInstance 使用IL Emit替换Activator.CreateInstance - Using IL Emit to replace Activator.CreateInstance 使用Log4net和Activator.CreateInstance - using Log4net and Activator.CreateInstance
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM