我正在创建一个类,用于确定要调用多少个已注册的WCF客户端回调。当客户端向服务器注册时,它会提供它感兴趣的令牌。然后,类在字典中存储令牌到IClientCallback接口的映射。
该方法及其测试类如下所示
public class Router
{
private IDictionary<int, IClientCallBack> clients;
public Router()
{
clients = new Dictionary<int, IClientCallBack>();
}
public Router(IDictionary<int, IClientCallBack> clients)
{
this.clients = clients;
}
public bool Register(int token, IClientCallBack client)
{
if (!clients.ContainsKey(token))
{
clients.Add(token, client);
return true;
}
return false;
}
}
如何测试客户端是否已成功注册到路由器? 我想我可以假设如果函数返回true,它是成功的(但是什么是停止函数体只是“return true;”?)或者我可以将客户端Dictionary注入类的构造函数和我的test我可以检查clients.Count是否等于1,如下所示。
[TestMethod]
public void RegisterTest()
{
IDictionary<int, IClientCallBack> clients = new Dictionary<int, IClientCallBack>();
var router = new Router(clients);
var client = new Mock<IClientCallBack>().Object;
var success = router.Register(4, client);
Assert.IsTrue(success);
Assert.AreEqual(1, clients.Count);
Assert.AreEqual(clients[4], client);
}
虽然上面的测试似乎很好,但是使用依赖注入来插入集合似乎有些过分,所以我可以测试它。然而,它确实使测试更容易和更准确(当测试类的其他方法时)。
这是测试此方法的推荐方法,还是过度杀伤?
答案 0 :(得分:2)
那么,你为什么要关心字典的内容是什么?如果你注射了它,那么你可能会非常关心 - 但那时它是API的一部分。如果你可以在没有构造函数的情况下使用字典,那么只需测试字典内容的实际效果。
所以,如果你为同一个令牌调用两次注册,它应该返回false,对吗?做个测试。据推测,还有其他与令牌有关的事情 - 因此在令牌已经注册时以及何时没有注册时进行测试。
这样说:如果有人想使用令牌/客户端对的链接列表重新实现该类,那会破坏该类的有用功能吗?我怀疑不是 - 所以你的测试可能不应该关心。
现在,在我开始听起来过于学术化之前,我不是那些认为单元测试应该始终如一的人,总是只接触公共方法而不关心实现。他们不是黑盒测试。有时知道实现可以使测试一个复杂的逻辑位变得容易得多,即使它通常只是通过实际上更多地解决它的东西暴露。但是在你提出的情况下,我真的只会坚持“就外面的世界所能做的那样做它能做什么”的方法。
答案 1 :(得分:0)
基本上,如果您正在查看内部数据结构,那么您的测试正在检查特定实现,而不是声明该类的预期行为。
如果这是我的测试,我宁愿对模拟对象设置一些期望,然后在Router类上调用一些验证这些期望的方法。
答案 2 :(得分:0)
好点Jon。上面的课程与我今天下午的工作尝试略有简化。在实际的测试代码中,我提供了一个或多个令牌来注册IClientCallBack。每个令牌都应该有一个字典条目。想法是Resolve(int token)将返回映射的IClientCallBack ...
如果我的方法是
,那么扔我的是什么public bool Register(int token, IClientCallBack client)
{
return true;
}
我的测试将错误地成功。现在,我可以在类中调用另一个方法来验证IClientCallBack是否被正确映射,例如调用Resolve,但是我会在一次测试中测试不同的方法,我认为这很糟糕业力?
以前我刚刚测试过该方法会返回true,但是有声音告诉我,如果我编写方法来传递,它可能不一定按我想要的那样做。
也许我只是弄乱TDD点:)