c#算法为单元测试创建伪造的加拿大社会安全号码(SIN)
本文关键字:安全 社会 号码 SIN 加拿大 算法 单元测试 创建 伪造 | 更新日期: 2023-09-27 18:25:35
我需要用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.
这并不是一个真正的答案,但它很重要,而且评论中没有足够的空间,所以这里是
这听起来很像真实代码的目的是验证用户输入的SIN,并且您希望在测试套件中随机生成SIN来测试验证代码那错了
单元测试不应生成随机数据这并不意味着你根本不能使用数据;生成一组10000个好的SIN和10000个坏的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;
}
可能有一种方法可以通过算法生成一个有效的数字,但作为快速解决方案,您可以生成一个由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;
}
}
我认为他们用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.
因为最后你把所有的数字加起来,所以只有一个7
和16
对最终结果没有影响。
要生成大量有效的SIN,您可以生成随机的九位数,计算它们的"校验和",找到该校验和除以10的余数,并调整位置1、3、5、7或9中的一个或多个数字以获得正确的校验和。
您可以创建一个9个整数/数字的列表,生成前8个数字(随机数在0到9之间),然后将最后一个数字设置为一个值,以便相加的9个数字可以除以10。
这是在随机生成所有其他8位后计算第9位的方法
d9=10-(d1+d2+d3+d4+d5+d6+d7+d8)%10
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!");