c#算法为单元测试创​​建假加拿大社会安全号码(SSN)

时间:2013-07-30 16:57:29

标签: c# algorithm

我需要在c#中编写单元测试,以便为我们的应用程序生成假的加拿大SIN编号。 在搜索互联网后,这是我发现的。我甚至不知道怎么开始。特别是将每个顶部数字与下面的数字相乘会让我感到困惑,因为它不是直接的乘法。提前感谢您的帮助。感谢。

以下是我从谷歌搜索获得的算法。

Algorithm _

Social Insurance Numbers are validated via a simple checksum process.

Let's use this fictitious SIN to demonstrate:

    046 454 286  <  Try substituting your SIN

    046 454 286  \  Multiply each top number
    121 212 121  /  by the number below it..
    -----------
    086 858 276  <  and get this.
             ^
             Notice here that 8*2=16, add 1 and
             6 together and get 7. If you get a
             2 digit # add the digits together.

Add all of these digits together.

0+8+6+8+5+8+2+7+6=50
                  /\
                If the SIN is valid this # will
                be evenly divisible by 10. This
                is a 'valid' SIN.

5 个答案:

答案 0 :(得分:7)

这并不属于答案,但它很重要,评论中没有足够的空间,所以这里......


这听起来非常像真实代码的目的是验证用户输入的SIN,并且您希望在测试套件中随机生成SIN以测试验证代码。 那是错的。

单元测试不应生成随机数据。这并不意味着您根本不能使用数据;生成一组10,000个好的SIN和一万个坏的SIN 一次,保存这些数据,然后针对您的验证方法编写一个测试,以便为所有这些获得正确的结果,这是完全正常的。重要的规则是:

测试通过还是失败不应该取决于随机发生器在特定运行中生成的数据。

主要是测试失败必须以可重复的方式继续失败,直到您修复导致失败的代码。如果测试数据是随机的,则无法保证这一点。

稍后,您可能仍会发现验证程序因特定SIN而失败的错误。此时的正确响应是将SIN永久添加到测试数据中。然后修复代码。通过这种方式,您也可以免受回归的影响。

您可能仍然希望仅使用它来生成初始测试数据,这很好,但我认为找到一个已经可以为您提供数据集的网站要容易得多。以下是Google的快速结果:
http://www.testingmentor.com/tools/tool_pages/ssnsin.htm

而且,只是为了好玩,这是我的验证方法的样子(未经测试,直接在回复窗口中输入):

bool IsValidSIN(string SIN)
{ 
   //normalize
   SIN = SIN.Trim();
   //account for common input formats that use - . or space as separators
   SIN = SIN.Replace(" ", "").Replace("-","").Replace(".","");

   //basic validations
   if (string.IsNullOrEmpty(SIN)) return false;
   if (SIN.Length != 9) return false;
   if (!SIN.All(c => char.IsDigit(c) ) return false;

   //checksum - we already know here that all characters are digits
   int multiplier = 0;
   int sum = 0;
   foreach (int d in SIN.Select(c => (int)c))
   {
      sum += (d * ((multiplier % 2) + 1)).ToString().Select(c => (int)c).Sum();
      multiplier ++;
   }
   return sum % 10 == 0;
}

答案 1 :(得分:3)

可能有一种方法可以通过算法生成有效数字,但作为快速修复,您可以生成9个整数的随机序列,然后对其进行验证。重复,直到您有一个有效的系列。这是一个完整的实现:

class SinGenerator
{
    Random r = new Random();

    /// <summary>
    /// Generates a valid 9-digit SIN.
    /// </summary>
    public int[] GetValidSin()
    {
        int[] s = GenerateSin();

        while (!SinIsValid(s))
            s = GenerateSin();  

        return s;
    }

    /// <summary>
    /// Generates a potential SIN. Not guaranteed to be valid.
    /// </summary>
    private int[] GenerateSin()
    {
        int[] s = new int[9];

        for (int i = 0; i < 10; i++)
            s[i] = r.Next(0, 10);

        return s;
    }

    /// <summary>
    /// Validates a 9-digit SIN.
    /// </summary>
    private bool SinIsValid(int[] sin)
    {
        if (sin.Length != 9)
            throw new ArgumentException();

        int checkSum = 0;

        for (int i = 0; i < sin.Length; i++)
        {
            int m = (i % 2) + 1;
            int v = sin[i] * m;
            if (v > 10)
                checkSum += 1 + (v - 10);
            else
                checkSum += v;
        }

        return checkSum % 10 == 0;
    }
}

答案 2 :(得分:1)

我认为他们7取代16的原因是他们的空间不足:如果他们放16而不是7,其他数字会不再排队。

我认为这可以更好地说明发生的事情:

046 454 286  \  Multiply each top number
121 212 121  /  by the number below it..
-----------
000 000 010  <  and get this (tens are on the top)
086 858 266  <  ... ones are on the bottom.

由于最后您将所有数字相加,因此只有一个716相比,不会对最终结果产生影响。

要生成大量有效的SIN,您可以生成随机的九位数字,计算它们的“校验和”,找到除以十的校验和的余数,并调整位置1,3中的一个或多个数字,5,7或9,以获得正确的校验和。

答案 3 :(得分:0)

您可以创建一个包含9个整数/数字的列表,使用0到9之间的随机数生成前8个数字,然后将最后一个数字设置为一个值,以便加上9个数字可以除以10。

这是在randmonly生成所有其他8位数后计算数字的方法

d9 = 10 - (d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8)%10

答案 4 :(得分:0)

var nas = "046 454 286".Where(x => !Char.IsWhiteSpace(x)).ToList();
var check = "121 212 121".Where(x => !Char.IsWhiteSpace(x)).ToList();

var result = "";
for(int i = 0; i < nas.Count(); ++i){
    int tmp = (int)(nas[i]) * (int)(check[i]);
    var val = tmp < 10 ? tmp : tmp - 9;
    result += val;
}

var sum = result.Aggregate(0, (acc, item) => acc + (int)(item));
if(sum % 10 == 0) Console.WriteLine("valid!"); else Console.WriteLine("invalid!");