编写C#nunit测试而无需访问其余代码

时间:2016-12-16 17:18:16

标签: c# unit-testing tdd nunit moq

我有一个Person类和接口:

interface IService
{
    double GetAccDetails(int personId);
}

public class Person
{
    private int _personId;
    private IService _service;

    public Person(int personId, IService service)
    {
        _personId= personId;
        _service = service;
    }

    public double Amount {get; set;}

    public void UpdateBackingAcc()
    {
        Amount = _service.GetAccDetails(_personId);
    }
}

我必须用nunit测试来覆盖这段代码,但是我无法访问该服务,只能访问我发布的代码。

所以我的问题是:

  1. 为了编写单元测试,我应该进行moque吗?如果是的话,它总会给我一些静态价值,所以我不会看到它有多大的利润。

  2. 可以为给定的界面创建哪种测试?我假设,其中一个测试可能会尝试使用personId1并获得一些静态值,然后它可以使用personId2并可能获得另一个值,然后检查金额是否已更新。所以,如果这是正确的,那么这可能只是1次单元测试。

  3. 检查值是否为负值可能是有意义的...也许值为0 ......

    还有其他想法吗?

3 个答案:

答案 0 :(得分:2)

您的班级Person有一个公共构造函数,public get \ set属性和public方法。建议是测试该类的公共接口。对于你的课程,你可以测试:

  1. Ctor,您应该对{null}验证IService。改进您的代码以测试它。
  2. 您可以测试您的财产获取和设置
  3. 您可以验证调用UpdateBackingAcc的时间,IService将被调用,并且该值将保留在Amount属性中。

答案 1 :(得分:1)

就编写单元测试而言,由于您正在与第三方服务进行互动,因此无法控制它,因此模拟是您的最佳选择。

我个人建议围绕该服务编写一个包装类,您可以控制与该服务的交互。

我可以使用一个测试:测试模拟服务返回的值是否已分配给Amount。如果数字为零,正数或负数并不重要,因为所有这些情况都经过相同的代码路径。

您可能希望集成测试与服务进行真实交互,主要是为了测试您确实正在与服务进行通信并获取值。

答案 2 :(得分:1)

1 /是服务是被测试类的外部依赖,它应该被模拟。

2 /接口无法测试,因为它没有代码。人类可以进行测试。

我同意你的看法。在这里,您可以测试constructor并证明字段设置正确。但只有合理的测试我可以做以下测试。它测试Amount包含执行方法UpdateBackingAcc后从服务返回的值。

[TestMethod]
public void UpdateBackingAcc_WhenCalled_AmountContainsValueReturnedFromService()
{
    Mock<IService> serviceMock = new Mock<IService>();
    const double expectedResult = 100;
    const int personId = 200;
    serviceMock.Setup(s => s.GetAccDetails(It.Is<int>(id => id == personId)))
        .Returns(() => expectedResult);
    Person person = new Person(personId, serviceMock.Object);

    // Act
    person.UpdateBackingAcc();

    // Assert
    double actualResult = person.Amount;
    Assert.AreEqual(expectedResult, actualResult);
}

这里我们没有关于该服务的所有信息。例如。使用无效personId调用时服务返回什么?考虑到这一点,可以编写更多的测试,例如。

  • UpdateBackingAcc_PersoneIdValid_AmountContainsValueReturnedFromService
  • UpdateBackingAcc_PersoneIdInvalid_ThrowsException
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void UpdateBackingAcc_PersoneIdInvalid_ThrowsException()
{
    // Arrange
    Mock<IService> serviceMock = new Mock<IService>();
    const int invalidPersonId = -1;
    serviceMock.Setup(s => s.GetAccDetails(It.Is<int>(i => i == invalidPersonId)))
        .Throws<InvalidOperationException>();
    Person person = new Person(invalidPersonId, serviceMock.Object);

    // Act
    person.UpdateBackingAcc();

    // Assert
    // Throws exception
}
相关问题