简体   繁体   中英

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.

Is it possible to mock a method with using of 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. 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:

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:

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. 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):

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM