C# 如何为公平分配算法创建单元测试?

C# 如何为公平分配算法创建单元测试?,c#,unit-testing,tdd,nunit,C#,Unit Testing,Tdd,Nunit,我有以下算法: 给定一个帐户列表,我必须在系统用户之间公平划分这些帐户 现在,为了减轻用户的工作量,我必须在几天内将他们分开。 因此,如果一个帐户有服务订单,则必须将其插入将在547天(一年半)内分发的列表中。如果帐户没有服务订单,则必须将其插入将在45天(一个半月)内分发的列表中。 我使用的LINQ扩展来自: 公共静态IEnumerable分发( 此IEnumerable源(IList存储桶) { var taged=source.Select((item,i)=>new{item,tag=i

我有以下算法:
给定一个帐户列表,我必须在系统用户之间公平划分这些帐户
现在,为了减轻用户的工作量,我必须在几天内将他们分开。
因此,如果一个帐户有服务订单,则必须将其插入将在547天(一年半)内分发的列表中。如果帐户没有服务订单,则必须将其插入将在45天(一个半月)内分发的列表中。
我使用的LINQ扩展来自:

公共静态IEnumerable分发(
此IEnumerable源(IList存储桶)
{
var taged=source.Select((item,i)=>new{item,tag=i%bucket.Count});
var GROUBLED=从标记中的t开始
按桶对t.项目进行分组[t.标记];
分组返回;
}
我可以保证它是有效的。
我的问题是,我真的不知道如何对所有这些情况进行单元测试。
我可能有5个用户和2个帐户,这可能不足以在一年半甚至一个半月内拆分。
我可能有547个帐户和547个系统用户,因此每个帐户每天都由每个系统用户处理。

基本上我不知道我应该创建什么样的数据集,因为似乎有太多的选项,我应该断言什么,因为我不知道分布将如何。

从边界条件(方法输入的自然限制)和任何已知的角点情况开始(方法以意外的方式运行的地方,您需要特殊代码来说明这一点)

例如:

  • 当帐户为零时,该方法的行为如何
  • 零用户
  • 只有一个帐户和用户
  • 547个帐户和547个用户
听起来你已经知道这里的许多预期边界条件。最初很难想到这些情况,但在开发方法时,你可能已经碰到了其中的一些。它们自然也会通过手动测试——每次你发现一个bug,这都是一个新的必要测试


一旦你测试了bounday条件和角落案例,你还应该看看其他情况的“公平”样本——比如你的5个用户和2个帐户。你不能(或者至少,可以说不需要)测试该方法中所有可能的输入,但您可以测试具有代表性的输入样本,例如帐户分配不均。

我认为您的问题的一部分是您的代码描述了您如何解决问题,而不是您试图解决的问题。您当前的实现是确定性的,并为您提供了答案r、 但您可以轻松地将其与另一个“公平分配者”交换,这将为您提供一个细节不同的答案(可能不同的用户将分配不同的帐户),但满足相同的要求(分配是公平的)。
一种方法是关注“公平”的含义。与其检查当前实现的确切输出,不如重新设计它,使其在较高的层次上看起来像:

public interface IAllocator
{ IAllocation Solve(IEnumerable<User> users, IEnumerable<Account> accounts); }
公共接口定位器
{IAllocation Solve(IEnumerable用户,IEnumerable帐户);}

并编写测试,验证用户帐户的具体实现,但验证分配是否公平,具体定义如下:“每个用户都应该分配相同数量的帐户,正负一个”。定义什么是公平,或者你的算法的确切目标是什么,应该有助于你确定感兴趣的角落案例。制定更高层次的目标(分配应该公平,而不是具体的分配)应该允许您轻松地交换实现并验证分配器是否正在执行其工作。

问题是我无法判断输出将是什么。对于两个调用,输出可能相同,但可能完全不同。假设我有两个帐户A和B,我还有两个系统用户John和Bob。甚至不考虑“他们有没有服务订单?无论何时,只要John和Bob被分配到帐户A,Bob和帐户B,分配都是公平的,反之亦然。那么,我怎么能检查一些不是幂等的东西呢?”我想问一下,但后来我看了算法,它看起来是确定性的。它真的需要是非确定性的吗ic?也就是说,随机性是一种业务需求吗?如果它必须是随机的,你能模拟随机发生器,允许方法本身的行为与随机性分离吗?@尽管我仍在努力了解两个具有相同输入的调用如何不会给出相同的输出。@DavidHall:这不是业务需求就我而言,nt。然而,单元测试不应该关心实现细节,只关心预期结果。如果引入了一些随机性,允许测试中断可能是一种有效的折衷。你如何判断算法是确定性的?所有这些关于赋值是否是确定性的讨论都暗示着这里有一个隐式的概念等待被发现和明确。也许作为一个IASignmentStrategy可以注入SUT。
public interface IAllocator
{ IAllocation Solve(IEnumerable<User> users, IEnumerable<Account> accounts); }