如何将模拟接口对象传递给主类C#

时间:2018-06-26 05:52:16

标签: c# unit-testing interface moq

我有以下代码:

    public interface Iinterface
    {
        Task<bool> RetrieveFromDataBase();
    }
    public class Class1 : Iinterface
    {
        public async Task<bool> RetrieveFromDataBase()
        {
            //do something
            return true;
        }
    }
    public class AnotherClass
    {
        Class1 c = new Class1();       
        public AnotherClass(Class1 obj)
        {
           c = obj;
        }
        public async Task<bool> ExecuteData()
        {
            var result = await c.RetrieveFromDataBase();
            if (result)
            {
                //do some calculation
            }
            return true;
        }
    }

现在,我正在尝试为ExecuteData方法编写测试用例。在此方法中,我需要绕过RetrieveFromDataBase方法。所以我正在尝试嘲笑它。这是我编写的以下代码。

    [TestClass()]
    public class AnotherClassTests
    {
        [TestMethod()]
        public async Task ExecuteDataTest()
        {
            Task<bool> retValue = RetrieveFromDataBaseMoq(); // this returns true 
            var moq = new Mock<Iinterface>();
            moq.Setup(x => x.RetrieveFromDataBase()).Returns(retValue);

            AnotherClass obj = new AnotherClass((Class1)moq.Object); // error thrown from here
            var result = await obj.ExecuteData();
            Assert.IsTrue(result);
        }
    }

完成的模拟成功,即不会引发任何错误。我在这里面临的问题是,当我将此模拟对象传递给构造函数一个参数时,它将引发错误System.InvalidCastException:无法将对象“ Castle.Proxies.Iinterface”转换为类型“ Class1”。

我知道它无法将模拟接口转换为具体的类类型。但是,有没有一种方法可以纠正此错误,或者无论如何将模拟对象传递给主类。

非常感谢!

1 个答案:

答案 0 :(得分:3)

您应将变量c声明为Iinterface。这是使用接口的优点之一。您应该依赖于contract(interface),而不是具体的实现。之后,您就不必再依赖于具体的课程了。

 public class AnotherClass
{
    Iinterface c; //I removed the default new since it will get assigned in constructor     

    public AnotherClass(Iinterface obj)
    {
       c = obj;
    }

    public async Task<bool> ExecuteData()
    {
        var result = await c.RetrieveFromDataBase();
        if (result)
        {
            //do some calculation
        }
        return true;
    }
}
  

我在这里面临的问题是,类Class1还具有一些其他方法和变量,这些方法和变量未在接口中声明。

您可以在Class1内进行合成,然后将TInterface作为依赖项移到Class1内。请记住,界面是您在单元测试中会被嘲弄的

public class Class1 
{ 
    public TIinterface tinterface{get;private set;}
    public Class1(TIinterface interface)
    {
        tinterface= interface;
    }
}
public class YourCustomImplementation:TIinterface 
{
   public async Task<bool> RetrieveFromDataBase()
   {
        //do something
        return true;
   }
}



public class AnotherClass
{
    Class1 c = new Class1();       
    public AnotherClass(Class1 obj)
    {
       c = obj;
    }
    public async Task<bool> ExecuteData()
    {
        var result = await c.tinterface.RetrieveFromDataBase();
        if (result)
        {
            //do some calculation
        }
        return true;
    }
}