我有一个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测试来覆盖这段代码,但是我无法访问该服务,只能访问我发布的代码。
所以我的问题是:
为了编写单元测试,我应该进行moque吗?如果是的话,它总会给我一些静态价值,所以我不会看到它有多大的利润。
可以为给定的界面创建哪种测试?我假设,其中一个测试可能会尝试使用personId1
并获得一些静态值,然后它可以使用personId2
并可能获得另一个值,然后检查金额是否已更新。所以,如果这是正确的,那么这可能只是1次单元测试。
检查值是否为负值可能是有意义的...也许值为0 ......
还有其他想法吗?
答案 0 :(得分:2)
您的班级Person
有一个公共构造函数,public get \ set属性和public方法。建议是测试该类的公共接口。对于你的课程,你可以测试:
IService
。改进您的代码以测试它。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
}