【问题标题】:Testing a service using mock repository objects使用模拟存储库对象测试服务
【发布时间】:2013-05-28 19:48:10
【问题描述】:

我正在框架内测试服务。

为了初始化服务,我使用了模拟存储库对象。

ServiceTest.cs

private IRepository _repository;
private IService _service;
private List<Object> _objects;

[TestInitialize]
public void Initialize()
{
  _repository = new Mock<IRepository>().Object;

  _service = new Service(repository);

  _objects = new List<Object>()
  {
      new Object { Name = "random", ID = 1 },
      new Object { Name = "not so random", ID = 1},
      new Object { Name = "random", ID = 2 },
      new Object { Name = "not so random", ID = 2}
  };

  //attempt at mocking the repository
  _repository.Setup(r => r.GetObjects(It.IsAny<string>(), It.IsAny<int>())).Returns(_objects.Where(o => o.Name == _objects.Name && o.ID == _objects.ID).ToList());
}

[TestMethod]
public void GetObjects_ReturnObjectsList()
{
    //Arrange
    var name = "random";

    //Act
    var objects = _service.RetrieveObjects(name, 2);

    //Assert
    Assert.AreEqual(name, objects.Single().Name);
 }

但是,当我测试服务时,我得到了ArgumentNullExceptions。设置为存储库方法调用的变量返回null,并最终在运行业务逻辑时抛出错误。

Service.cs

    public List<Objects> RetrieveObjects(string name, int id) 
    {   
      var getObjects = repository.GetObjects(name, id); //getObjects return null

      DoLogic(getObjects); //ArgumentNullException is thrown here

      return getObjects; 
    }

我查找了有关模拟存储库的信息,但似乎我需要设置很多东西来测试。我想知道设置是否值得。

为什么我收到ArgumentNullExceptions?有没有办法测试调用存储库的方法?

【问题讨论】:

  • 你想测试什么?服务还是存储库?你在嘲笑 Repository,并断言它返回了什么?!
  • @lucky3 糟糕,我的意思是服务。

标签: c# unit-testing testing repository moq


【解决方案1】:

您只需要设置正在测试的内容,因此在您的安排中执行以下操作:

var repository = new Mock<IRepository>();
repository.Setup(x => x.GetObjects(It.IsAny<string>()).Returns("whatever getobjects should be returned, maybe a mock object or string");
var service = new Service(repository.Object());
//Continue your test

【讨论】:

  • 请查看我的问题中的更新。 repository 变量设置为 IRepository 对象,而不是 var。 new Mock&lt;Repository&gt;() 不适用于 IRepository
  • 忽略第一行,只使用mock Setup方法伪造GetObjects调用,然后将repository对象传递给服务。
  • 存储库调用完全位于不同的.cs 文件中是否重要?我已经设置了一个模拟存储库,但仍然收到null。请查看更新。
  • 不,存储库在另一个文件中并不重要。这里的区别在于您是创建单元测试还是集成测试。如果是后者,那么您可能应该重新考虑模拟存储库。如果它是一个单元测试并且您正在测试一个单独的代码单元,即 GetObjects(string parameter) 那么您应该模拟存储库并返回一个假对象,就像我在我的代码中所做的那样。设置上的 Returns 扩展应该返回您期望返回的内容。
  • +1 这种思维方式简洁明了。感谢您的帮助。
【解决方案2】:
var entity1 = new MyEntity();
var entity2 = new MyEntity();
var entities = new List<MyEntity>{entity1, entity2};

var mockRepository = new Mock<IRespository>();

mockRepository.Setup(r => r.GetObjects("some param")).Returns(entities);

var service = new Service(mockRepository.Object);

service.DoWork("some param");
//continue the test

【讨论】:

  • 存储库调用完全位于不同的.cs 文件中是否重要?我已经设置了一个模拟存储库,但仍然收到null。请查看更新。
  • 没关系。检查你的 DoLogic 方法,有什么不对劲的地方。上面的设置应该可以工作并返回正确的数据。检查“参数”是否也正常。
  • getObjects 被传入DoLogic 时,它是null。这是事实之前的情况。迄今为止在这方面没有取得任何进展。存储库类已经过彻底的单元测试,现在正在测试框架中的服务。
  • 请贴出服务实现,即repository是如何传入的。
  • 编辑后,我看不到存储库的设置位置。查看我提供的示例,我在您的代码中的任何地方都没有看到 mock.Setup。如果您没有将存储库设置为返回它需要返回的内容,则 mock 将返回 null。
【解决方案3】:

您应该单独测试您的 SUT(被测对象)。不要试图模拟现有的类,只使用接口。这样你就不会依赖其他可能有问题的对象。通常,您将无法设置用作模拟的现有类的回调和返回。模拟接口允许您控制和预测返回值。

因此,在您的特定情况下,您应该按照@ianaldo21 的建议进行操作,我只需将第一行更改为:

var repository = new Mock<IRepository>();

然后进行设置,并将 repository.Object 传递给 Service。

您应该测试 SUT 的行为和与其他对象的交互,而不是断言 SUT 的状态。所以你可以有这样的东西:

repository.Verify(x => x.GetObjects("test"));

这样,您通常需要更少的测试设置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-22
    • 2021-09-14
    • 2021-02-13
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多