一、xUnit 单元测试
官网地址:Home > xUnit.net
1、概述
1.1、新建个控制台项目
public class Class1
{
public int Add(int x, int y)
{
return x + y;
}
}
2、建个xUnit测试项目
public class UnitTest1
{
[Fact]
public void Test1()
{
Class1 class1 = new Class1();
int sum = class1.Add(2, 3);
Assert.Equal(5, sum);
}
}
鼠标放到方法上,右键运行测试即可
2、用法
2.1、基础应用
public class UnitTest1
{
private readonly ITestOutputHelper _outputHelper;
public UnitTest1(ITestOutputHelper testOutput)
{
_outputHelper = testOutput;
}
[Fact]
//[Trait("name","kawa1")]
public void Test1()
{
_outputHelper.WriteLine("第一个测试");//自定义测试输出信息
Class1 class1 = new Class1();
int sum = class1.Add(2, 3);
Assert.Equal(5, sum);//以下断言皆为true
string name = "come kawa";
Assert.True(1==1);
Assert.StartsWith("come",name);
Assert.Contains("ka", name);
Assert.NotEqual("come ka", name);
Assert.Matches(@"^[a-z]*\s[a-z]*", name);
Assert.InRange(sum, 3.1, 6.9);//是否在某一范围
Assert.NotNull(name);
Assert.IsType<Class1>(class1);
}
}
[Fact(Skip = "不跑这个测试")]//忽略测试
[Trait("name","kawa1")] //分组
2.2、数据驱动测试
1、
[Theory]
[InlineData(1,2,3)]
[InlineData(3,4,7)]
[InlineData(4,2,6)]
public void Test2(int x, int y, int except)
{
int act = new Class1().Add(x, y);
Assert.Equal(act, except);
}
2、
[Theory]
[MemberData(nameof(Class1.ListTest),MemberType = typeof(Class1))]
public void Test3(int x, int y, int except)
{
_outputHelper.WriteLine("Test3测试");//自定义测试输出信息
int act = new Class1().Add(x, y);
Assert.Equal(except, act);
}
public static List<object[]> ListTest = new List<object[]> //需要是object类型且是静态
{
new object[] { 1, 2 ,3},
new object[] { 2, 3 ,5 },
new object[] { 3, 6 ,9 }
};
3、自定义Data Attribute
[Theory]
[DataTest]
public void Test4(int x, int y, int except)
{
_outputHelper.WriteLine("Test4测试");//自定义测试输出信息
int act = new Class1().Add(x, y);
Assert.Equal(except, act);
}
public class DataTestAttribute: DataAttribute
{
//继承DataAttribute,并重写GetData
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] { 0, 100, 100 };
yield return new object[] { 1, 100, 101 };
yield return new object[] { 200, 100, 300 };
yield return new object[] { 15, 100, 115 };
}
}
二、加密解密
1、MD5
MD5 是一种快速且简单的哈希算法,适用于校验和验证数据完整性
MD5 并不被视为一种加密方法,而是一种哈希算法。加密和解密是双向过程,即数据可以被加密成密文,然后密文可以被解密回原文。而哈希是单向的,即数据可以被哈希成一个固定长度的字符串(哈希值),但这个哈希值不能被“解密”回原始数据。
public static string MD5Encrypt32(string password)
{
StringBuilder pwd = new StringBuilder();
MD5 md5 = MD5.Create(); //实例化一个md5对象
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));//计算字节数组的 MD5 哈希值
for (int i = 0; i < s.Length; i++)
{
pwd.Append(s[i].ToString("X"));//转换成十六进制
}
return pwd.ToString();
}
Console.WriteLine(MD5Encrypt32("kawa comeon"));//CBDAA6E875938D54C6236A7BE6B07D5D
虽然 MD5 计算简单且速度较快,但由于其存在碰撞漏洞(即不同的输入可能产生相同的哈希值),不再推荐用于安全相关的应用,如密码存储和数字签名。对于这些应用,建议使用更安全的哈希算法,如 SHA-256 或 bcrypt。
2、SHA-256
SHA-256 是一种比 MD5 更安全的哈希算法,生成 256 位的哈希值。
public static string SHA256Encrypt(string password)
{
StringBuilder pwd = new StringBuilder();
SHA256 sha256 = SHA256.Create();//实例化一个SHA256对象
byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));//计算字节数组的 SHA256 哈希值
for (int i = 0; i < bytes.Length; i++)
{
pwd.Append(bytes[i].ToString("X"));//转换成十六进制
}
return pwd.ToString();
}
Console.WriteLine(SHA256Encrypt("kawa comeon"));//797DB2635DE1EACB4323E1C6B634B868933DD79EE56B1019C458E735D52AA5
3、HMAC(哈希消息认证码)
HMAC 使用一个密钥和哈希函数(如 SHA-256)来生成消息认证码,用于确保消息的完整性和真实性。
public static string HMAC_SHA256Encrypt(string password, string key)
{
StringBuilder pwd = new StringBuilder();
using (HMACSHA256 hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))//实例化一个HMACSHA256对象
{
byte[] bytes = hmacSha256.ComputeHash(Encoding.UTF8.GetBytes(password));//计算字节数组的 HMACSHA256 哈希值
for (int i = 0; i < bytes.Length; i++)
{
pwd.Append(bytes[i].ToString("X"));//转换成十六进制
}
return pwd.ToString();
}
}
Console.WriteLine(HMAC_SHA256Encrypt("kawa comeon","1234567890")); //BC4B4D439B607A6CBD58EA749A5ADE814ABDFE1AB33F91782551B47F56C84E14
4、AES 对称加密
AES(Advanced Encryption Standard)是一种对称加密算法,它使用相同的密钥进行加密和解密。AES 是当今应用最广泛的加密标准之一,提供了高效的加密和解密功能,适用于多种应用场景。
基本概念
- 对称加密:加密和解密使用相同的密钥。
- 密钥:加密和解密过程中使用的秘密信息。
- 初始化向量(IV):在某些加密模式下使用的随机数据块,确保相同的明文在每次加密时产生不同的密文。
加密模式
CBC(Cipher Block Chaining):每个明文块在加密前与前一个密文块进行异或操作,使用 IV 初始化。
//加密
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
byte[] encrypted;
using (Aes aesAlg = Aes.Create())//使用 Aes.Create() 方法创建一个 AES 实例。
{
//AES 实例会自动生成密钥和初始化向量(IV),你也可以手动设置这些值。
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);//创建 AES 加密转换器 (ICryptoTransform encryptor)
//使用 CryptoStream 和 MemoryStream 进行加密,并将加密后的数据存储在字节数组中
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
return encrypted;
}
//解密
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);//创建 AES 解密转换器 (ICryptoTransform decryptor)
//使用 CryptoStream 和 MemoryStream 进行解密,并将解密后的数据转换回字符串
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
return plaintext;
}
//Main方法中
string original = "kawa comeon";
using (Aes aes = Aes.Create())
{
// 加密
byte[] encrypted = EncryptStringToBytes_Aes(original, aes.Key, aes.IV);
string encryptedText = Convert.ToBase64String(encrypted);
Console.WriteLine($"Encrypted: {encryptedText}");//Encrypted: kSFTZEaY3N8hIahM7LjvHw==
// 解密
string decrypted = DecryptStringFromBytes_Aes(encrypted, aes.Key, aes.IV);
Console.WriteLine($"Decrypted: {decrypted}");//Decrypted: kawa comeon
}
密钥和 IV 的管理:密钥和 IV 是加密和解密过程中最重要的部分,需要妥善保管。通常,密钥应存储在安全的地方,如环境变量、Azure Key Vault 等。