3

我需要用 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.
4

5 回答 5

8

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


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

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

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

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

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

您可能仍想使用它来生成初始测试数据,这很好,但我认为找到一个已经可以为您提供数据集的网站要容易得多。这是一个快速的谷歌结果:
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;
}
于 2013-07-30T17:26:32.033 回答
4

可能有一种方法可以通过算法生成一个有效数字,但作为一种快速修复,您可以生成一个由 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 < 9; i++)
            s[i] = r.Next(0, 10);

        return s;
    }

    /// <summary>
    /// Validates a 9-digit SIN.
    /// </summary>
    /// <param name="sin"></param>
    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;
    }
}
于 2013-07-30T17:14:51.843 回答
1

我认为他们放置的原因716空间不足:如果他们放置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.

由于最后您将所有数字相加,因此单个7vs.16不会对最终结果产生影响。

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

于 2013-07-30T17:04:42.970 回答
0

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

这是在随机生成所有其他 8 位数字后计算第 9 位数字的方法

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

于 2013-07-30T17:15:57.853 回答
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!");
于 2013-07-30T18:00:07.040 回答