【问题标题】:How to mock the dependency inside constructor?如何模拟构造函数内部的依赖关系?
【发布时间】:2020-04-16 08:32:10
【问题描述】:

我需要测试函数 GetPollData() 并且我已经编写了 Apitest 类并创建了该类的模拟对象并创建了一个测试方法 将检查返回值和预期值的 TestGetPollData() 是
是否相等。但我得到的返回值为 20 而不是预期的 10.我调试并检查了API内部创建的业务对象
类构造函数未被模拟,并且该依赖项返回 在类中初始化的值,而不是我想要的模拟值 返回。有什么方法可以模拟在内部创建的对象 构造函数或使 Apitest 按我的预期工作。我正在使用 nunit 测试框架。 请告诉我我做错了什么以及我应该怎么做?

 public class API
     {  
        public Business business { get; set; }

        public API()
        {
           business=new Business();
        }

        public int GetPollData()
        {
           return business.polltime();
        }
      }

 public class Business
   {
        public int polltime()
        {
        return Service.poll;
        }
   }    

 public class Service
    {
    public int poll=20;
    }

//API TEST CLASS
 public class Apitest
     {
        private Mock<API> api = new Mock<API>();
        API ApiObj = new ApiObj();

        // Testing the GetPollData method 
        public TestGetPollData()
          {
           api.Setup( x => x.GetPollData()).Returns(10);
           int value=ApiObj.GetPollData();
           Assert.AreEqual(10,value);
          }
       }

【问题讨论】:

  • 如果GetPollData 只是返回business.polltime(),为什么不只是测试Business

标签: c# moq


【解决方案1】:

对于使用 Moq 可以模拟的内容存在限制。此处将对此进行更详细的介绍。

Can I use moq Mock<MyClass> to mock a class , not an interface?

更常见的是将 Moq 与接口或至少一个抽象类一起使用。

我已经重构了您的代码,以便 API 实现接口 IAPI。然后模拟 IAPI。

我已更改您的测试方法,以便您从模拟对象而不是真实对象调用 GetPollData() 方法。

还建议将您对 Business 类的依赖项注入 API 的构造函数中,以便以后可以在需要时对其进行 Mock。我会让你这样做。

using Moq;
using NUnit.Framework;

namespace EntitlementServer.Core.Tests
{
    public interface IAPI
    {
        int GetPollData();
    }

    public class API : IAPI
    {
        public Business business { get; set; }

        public API()
        {
            business = new Business();
        }

        public int GetPollData()
        {
            return 20;
        }
    }

    public class Business
    {
        public int polltime()
        {
            return Service.poll;
        }
    }

    public static class Service
    {
        public static int poll = 20;
    }

    [TestFixture]
    public class Apitest
    {
        // Testing the GetPollData method 
        [Test]
        public void TestGetPollData()
        {
            var api = new Mock<IAPI>();
            api.Setup(x => x.GetPollData()).Returns(10);
            int value = api.Object.GetPollData();

            Assert.AreEqual(10, value);
        }
    }
}

【讨论】:

    【解决方案2】:

    你必须通过注入依赖来重构它。

    public class API { 
        public Business business { get; set; }
    
        public API( Business b )
        {
           business= b;
        }
    
        public int GetPollData()
        {
           return business.polltime();
        }
     }
    

    在测试中,将模拟的Business 传递给API,并测试模拟实例的polltime 是否被调用。

    【讨论】:

    • 有没有其他方法来模拟业务对象而不是模拟和注入它
    • 除非你使用 Autofac 之类的 IoC 容器,并重构 API 以使用容器。没有办法嘲笑它。不要继承API并重写构造函数,因为它的基础构造函数在构造时仍然被调用。
    猜你喜欢
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多