【问题标题】:How to assign a mocked object to a object in controller?如何将模拟对象分配给控制器中的对象?
【发布时间】:2016-03-28 13:35:26
【问题描述】:

我有一个控制器,其中包含一个 business 类,该类在内部具有对 datahandler 的依赖关系。为了测试那个商务舱,我需要模拟datahandler。设置完成后,我将使用模拟的datahandler 分配商务舱的datahandler。但是在调试时,业务类'datahandler 显示为 null ,我知道我应该使用构造函数来注入模拟对象。但是是否可以不使用任何构造函数注入来做到这一点?任何机构可以帮助我吗?

我的商务舱:

public class FooBusiness
{
  public static BarDataHandler _barDatahandler = new BarDataHandler();
  ...
}

测试类:

public class FooBusinessTest
{
  ...
  _mockedBarDataHandler = new Mock<IBarDataHandler>(){CallBase:true};

   public FooTestMeth()
   {
    //Arrange
    _mockedBarDataHandler.Setup(x=>x.Search(It.IsAny<int>).Returns(1);
    ...
    FooBusiness _fooBusiness = new FooBusiness();

    FooBusiness._barDatahandler = _mockedBarDataHandler.Object;

    //Act
    ...
   }
}

【问题讨论】:

  • 构造函数注入是一种方式,但您也可以设置属性。我不喜欢这个,但这是另一个问题。您需要删除 static 关键字并且 _barDatahandler 应该是 IBarDataHandler 类型。应该按预期工作....您是否有理由希望这个公共字段是静态的?
  • @Marc : 很久以前没有人编码过,我不应该更改业务类.. 你为什么不把这个放在答案中以便我可以接受?
  • 我发布了我的答案。如果需要,您可以标记为已回答。

标签: c# unit-testing asp.net-mvc-4 moq


【解决方案1】:

正如我所提到的,有多种方法可以满足您的需求。 个人比较喜欢Shyju的回答(Constructor Injection),但是如果不能改变构造函数,后面还是可以通过设置属性来改变实现:

商务舱:

public class FooBusiness
{
    private IBarDataHandler _barDatahandler = new BarDatahandler();

    public IBarDataHandler BarDatahandler
    {
        get { return _barDatahandler; }
        set { _barDatahandler = value; }
    }

    public int Search(int a)
    {
        return _barDatahandler.Search(a);
    }
}

测试类:

public class FooBusinessTest
{
    _mockedBarDataHandler = new Mock<IBarDataHandler>(){CallBase:true};

    public FooTestMeth()
    {
        //Arrange
        _mockedBarDataHandler.Setup(x => x.Search(It.IsAny<int>).Returns(1);

        FooBusiness fooBusiness = new FooBusiness();
        fooBusiness.BarDatahandler = _mockedBarDataHandler.Object;

        //Act
    }
}

如果您担心重构实现,最好先设置所有测试。之后,您可以以更安全的感觉进行重构:)

【讨论】:

    【解决方案2】:

    你需要将你的 dataHandler 依赖注入到FooBusiness

    如果您的BarDataHandler 不存在,您需要为您提取一个接口。

    interface IBarDataHandler
    {
      string GetUserToken(int id);
    }
    public class BarDataHandler : IBarDataHandler
    {
      public string GetUserToken(int id)
      {
         // to do :read from db and return
      }
    }
    

    并向FooBusiness 类添加一个构造函数,该类接受IBarDataHandler 的实现。

    public class FooBusiness
    {
      IBarDataHandler barDataHandler;
      public FooBusiness(IBarDataHandler barDataHandler)
      {
        this.barDataHandler=barDataHandler
      }
      public string GetUserToken(int id)
      {
        return this.barDataHandler.GetUserToken(id);
      }
    }
    

    您可以使用任何一种依赖注入框架,例如 Unity/Ninject/StructureMap 在您的应用运行时解析您的具体实现。

    您可以使用任何模拟框架(如 Moq)在您的单元测试中模拟 IBarDataHandler 的假实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-22
      • 2011-01-25
      • 2016-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      相关资源
      最近更新 更多