You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

751 lines
23 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;
using Xunit;
using Xunit.Extensions;
using Xunit.Serialization;
using Xunit.Abstractions;
using Xunit.Sdk;
using RedisStudyModel;
using RedisStuy;
namespace RedisStudyTest
{
/// <summary>
/// Redis Hash 类型测试
/// </summary>
public class RedisHashStudyTest : IDisposable
{
#region 初始化
private readonly ITestOutputHelper testOutput;
private IDatabase redisDatabase = null;
private RedisHashStudy hashStudy = null;
private List<Student> students;
private Student defaultStudent = null;
private string preHashKey = "RedisStudy:Student:";
private string defaultHashKey = "";
private int keyExpireSeconds = 20;
/// <summary>
/// 构造
/// </summary>
public RedisHashStudyTest(ITestOutputHelper output)
{
this.testOutput = output;
redisDatabase = RedisHelper.GetRedisDatabase();
hashStudy = new RedisHashStudy();
defaultStudent = new Student()
{
Id = 1,
Name = "王高峰",
Age = 18
};
defaultHashKey = preHashKey + defaultStudent.Id;
students = new List<Student>()
{
new Student()
{
Id = 1001,
Name = "王高峰",
Age = 11
},
new Student()
{
Id = 1002,
Name = "王高峰2",
Age = 22
},
new Student()
{
Id = 1003,
Name = "王高峰3",
Age = 33
},
new Student()
{
Id = 1004,
Name = "王高峰4",
Age = 44
},
new Student()
{
Id = 1005,
Name = "王高峰5",
Age = 55
},
};
DeleteExitsStudents();
}
#endregion
#region HashSet
/// <summary>
/// xUnit输出信息 测试
/// </summary>
[Fact(DisplayName = "HashSet 输出信息测试")]
public void HashSetOutputTest()
{
Assert.True(true);
testOutput.WriteLine("我是xUnit测试输出信息");
}
/// <summary>
/// 参数异常 测试
/// </summary>
[Fact(DisplayName = "HashSet 异常测试")]
public void HashSetExceptionTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//参数异常测试
Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(string.Empty, null));
Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet("", null));
Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(preHashKey + "-1", null));
Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(preHashKey + "-1", new HashEntry[] { }));
}
/// <summary>
/// 参数 When 测试
/// </summary>
[Trait("HashSet", "When")]
[Fact(DisplayName = "HashSet When参数测试")]
public void HashSetWhenTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//当前上下文不能使用: When.Exists
var id_When_NotExists_No = hashStudy.HashSet(redisKey, "Id", defaultStudent.Id + 1, When.NotExists);
Assert.True(id_When_NotExists_No);
var id_When_NotExists_Yes = hashStudy.HashSet(redisKey, "Id", defaultStudent.Id + 1, When.NotExists);
Assert.False(id_When_NotExists_Yes);
var id_When_Always_Exists = hashStudy.HashSet(redisKey, "Id", defaultStudent.Id + 1, When.Always);
Assert.False(id_When_Always_Exists);
var id_When_Always_NotExists = hashStudy.HashSet(redisKey, "Id4", defaultStudent.Id + 1, When.Always);
Assert.True(id_When_Always_NotExists);
}
/// <summary>
/// 添加一个默认学生 测试
/// </summary>
[Fact]
public void HashSetAddStudentTest()
{
string redisKey = preHashKey + defaultStudent.Id;
var studentEntries = new HashEntry[]
{
new HashEntry("Id",1),
new HashEntry("Name",defaultStudent.Name),
new HashEntry("Age",defaultStudent.Age),
};
//插入Sudent
var addHash = hashStudy.HashSet(redisKey, studentEntries, CommandFlags.None);
Assert.True(addHash);
//设置过期
redisDatabase.KeyExpire(redisKey, TimeSpan.FromSeconds(keyExpireSeconds));
}
/// <summary>
/// 添加一组初始化设置的学生 测试
/// </summary>
[Fact]
public void HashSetAddGroupStudentTest()
{
foreach (var temp in students)
{
string redisKey = preHashKey + temp.Id;
var studentEntries = new HashEntry[]
{
new HashEntry("Id", temp.Id),
new HashEntry("Name", temp.Name),
new HashEntry("Age", temp.Age),
};
//插入Sudent
var addStudent = hashStudy.HashSet(redisKey, studentEntries);
Assert.True(addStudent);
//设置过期
redisDatabase.KeyExpire(redisKey, TimeSpan.FromSeconds(keyExpireSeconds));
}
//清理删除
foreach (var temp in students)
{
redisDatabase.KeyDelete(preHashKey + temp.Id);
}
}
/// <summary>
/// 设置一个哈希字段 测试
/// </summary>
[Fact]
public void HashSetHashfieldTest()
{
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Id", defaultStudent.Id));
Assert.False(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Id", defaultStudent.Id));
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Name", defaultStudent.Name));
Assert.False(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Name", defaultStudent.Name));
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Age", defaultStudent.Age));
Assert.False(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Age", defaultStudent.Age));
}
/// <summary>
/// 设置一组哈希字段 测试
/// </summary>
[Fact]
public void HashSetGroupHashfieldTest()
{
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Id", defaultStudent.Id));
Assert.False(hashStudy.HashSet(preHashKey + defaultStudent.Id, "Id", defaultStudent.Id + 1));
var entrys = new HashEntry[]
{
new HashEntry("Name", defaultStudent.Name),
new HashEntry("Age", defaultStudent.Age),
};
var entrys2 = new HashEntry[]
{
new HashEntry("Name", defaultStudent.Name+"2"),
new HashEntry("Age", defaultStudent.Age+1),
};
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, entrys));
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, entrys2));
}
/// <summary>
/// 特例测试给key为空的哈希 设置字段
/// 结 果:添加或更新操作能成功,但是字段值插入不进去。
/// </summary>
[Fact]
public void HashSetForEmptyKeyTest()
{
Assert.True(hashStudy.HashSet(string.Empty, "Name", "wanggaofeng"));
redisDatabase.KeyDelete(string.Empty);
}
/// <summary>
/// 特例测试:给字段名为空串的哈希 设置字段
/// 结 果:添加或更新操作正常,只是字段键名为""
/// </summary>
[Fact]
public void HashSetForEmptyFieldTest()
{
Assert.True(hashStudy.HashSet(preHashKey + defaultStudent.Id, "", defaultStudent.Id));
Assert.False(hashStudy.HashSet(preHashKey + defaultStudent.Id, "", defaultStudent.Id + 1));
redisDatabase.KeyDelete(preHashKey + defaultStudent.Id);
}
#endregion
#region HashDecrement
/// <summary>
/// 字段值不是数字时,异常
/// 原注释:字段不为数据字,则改为数字
/// 实际执行:抛出异常,不知道是原注释错误,还是其它原因
/// </summary>
[Fact]
public void HashDecrementExceptionTest()
{
string redisKey = preHashKey + defaultStudent.Id;
Assert.True(hashStudy.HashSet(redisKey, "Name", "wanggaofeng"));
Assert.Throws<RedisServerException>(() => hashStudy.HashDecrement(redisKey, "Name", 1));
}
/// <summary>
/// 哈希表不存在
/// 则先创建哈希表再添加值为0的字段然后执行自减操作
/// </summary>
[Fact]
public void HashDecrementHashKeyTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//Key不存在先创建哈希表再添加值为0的字段然后执行自减操作
Assert.Equal(-1, hashStudy.HashDecrement(redisKey, "Id", 1));
//存在,直接自减
Assert.Equal(-1, hashStudy.HashGet(redisKey, "Id"));
}
/// <summary>
/// 自减字段不存在
/// 先添加字段值设为0然后执行自减操作
/// </summary>
[Fact]
public void HashDecrementHashFieldTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//字段不存在,则创建之
Assert.Equal(-1, hashStudy.HashDecrement(redisKey, "Age", 1));
Assert.Equal(-1, hashStudy.HashGet(redisKey, "Age"));
}
/// <summary>
/// 自减负数,则自增
/// </summary>
[Fact]
public void HashDecrementMinusTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//自减负数时,则自增
Assert.Equal(2, hashStudy.HashDecrement(redisKey, "Age", -2));
}
/// <summary>
/// 自减整数
/// </summary>
[Fact]
public void HashDecrementByIntTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//字段减少1
Assert.Equal(-1, hashStudy.HashDecrement(redisKey, "Age", 1));
//字段减少2
Assert.Equal(-3, hashStudy.HashDecrement(redisKey, "Age", 2));
}
/// <summary>
/// 自减浮点数
/// 断言应该用精度值在一个小范围内
/// </summary>
[Fact]
public void HashDecrementByDoubleTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//新字段时,可以用相等比较
var dec = hashStudy.HashDecrement(redisKey, "Age", 2.1);
var absDec = Math.Abs(-2.1 - dec);
Assert.Equal(0, absDec);
//已经存在的,浮点数,不使用相等比较,而改用两值相差一定的小范围
dec = hashStudy.HashDecrement(redisKey, "Age", 2.5);
absDec = Math.Abs(-4.6 - dec);
Assert.True(absDec < 0.01);
}
#endregion HashIncrement
#region HashIncrement
/// <summary>
/// 字段值不是数字时,异常
/// 原注释:字段不为数据字,则改为数字
/// 实际执行:抛出异常,不知道是原注释错误,还是其它原因
/// </summary>
[Fact]
public void HashIncrementExceptionTest()
{
string redisKey = preHashKey + defaultStudent.Id;
Assert.True(hashStudy.HashSet(redisKey, "Name", "wanggaofeng"));
Assert.Throws<RedisServerException>(() => hashStudy.HashIncrement(redisKey, "Name", 1));
}
/// <summary>
/// 哈希表不存在
/// 则先创建哈希表再添加值为0的字段然后执行自增操作
/// </summary>
[Fact]
public void HashIncrementHashKeyTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//Key不存在先创建哈希表再添加值为0的字段然后执行自减操作
Assert.Equal(1, hashStudy.HashIncrement(redisKey, "Id", 1));
Assert.Equal(1, hashStudy.HashGet(redisKey, "Id"));
}
/// <summary>
/// 自增字段不存在
/// 先添加字段值设为0然后执行自增操作
/// </summary>
[Fact]
public void HashIncrementHashFieldTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//字段不存在,则创建之
Assert.Equal(1, hashStudy.HashIncrement(redisKey, "Age", 1));
Assert.Equal(1, hashStudy.HashGet(redisKey, "Age"));
}
/// <summary>
/// 自增负数,则自减
/// </summary>
[Fact]
public void HashIncrementMinusTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//自增负数时,则自减
Assert.Equal(-2, hashStudy.HashIncrement(redisKey, "Age", -2));
}
/// <summary>
/// 自增整数
/// </summary>
[Fact]
public void HashIncrementByIntTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//字段减少1
Assert.Equal(1, hashStudy.HashIncrement(redisKey, "Age", 1));
//字段减少2
Assert.Equal(3, hashStudy.HashIncrement(redisKey, "Age", 2));
}
/// <summary>
/// 自增浮点数
/// 断言应该用精度值在一个小范围内
/// </summary>
[Fact]
public void HashIncrementByDoubleTest()
{
string redisKey = preHashKey + defaultStudent.Id;
//新字段时,可以用相等比较
var dec = hashStudy.HashIncrement(redisKey, "Age", 2.1);
var absDec = Math.Abs(2.1 - dec);
Assert.Equal(0, absDec);
//已经存在的,浮点数,不使用相等比较,而改用两值相差一定的小范围
dec = hashStudy.HashIncrement(redisKey, "Age", 2.5);
absDec = Math.Abs(4.6 - dec);
Assert.True(absDec < 0.01);
}
#endregion
#region HashGetAll
/// <summary>
/// 获取一个学生
/// </summary>
[Fact]
public void HashGetAllTest()
{
string redisKey = preHashKey + defaultStudent.Id;
var studentEntries = new HashEntry[]
{
new HashEntry("Id",1),
new HashEntry("Name",defaultStudent.Name),
new HashEntry("Age",defaultStudent.Age),
};
//插入Sudent
var addHash = hashStudy.HashSet(redisKey, studentEntries);
Assert.True(addHash);
var entries = hashStudy.HashGetAll(redisKey);
Assert.NotNull(entries);
Student myStudent = new Student()
{
Id = (int)entries.FirstOrDefault(e => e.Name == "Id").Value,
Name = entries.FirstOrDefault(e => e.Name == "Name").Value,
Age = (int)entries.FirstOrDefault(e => e.Name == "Age").Value,
};
Assert.True(myStudent.Id == defaultStudent.Id && myStudent.Name == defaultStudent.Name && myStudent.Age == defaultStudent.Age);
}
#endregion
#region HashGet
/// <summary>
/// 哈希表不存在时,获取字段值
/// </summary>
[Fact]
public void HashGetNotKkeyTest()
{
string redisKey = preHashKey + defaultStudent.Id;
var result = hashStudy.HashGet(redisKey, "Id");
Assert.False(result.HasValue);
}
/// <summary>
/// 字段不存在时,获取字段值
/// </summary>
[Fact]
public void HashGetNotHashfieldTest()
{
string redisKey = preHashKey + defaultStudent.Id;
hashStudy.HashIncrement(redisKey, "Id", 1);
var result = hashStudy.HashGet(redisKey, "Name");
Assert.False(result.HasValue);
}
[Fact]
public void HashGetTest()
{
string redisKey = preHashKey + defaultStudent.Id;
AddDefaultStudent();
Assert.Equal(1, hashStudy.HashGet(redisKey, "Id"));
Assert.Equal(defaultStudent.Name, hashStudy.HashGet(redisKey, "Name"));
Assert.Equal(defaultStudent.Age, hashStudy.HashGet(redisKey, "Age"));
}
#endregion
#region HashKeys
/// <summary>
/// 哈希不存在时获取所有字段的Key
/// </summary>
[Fact]
public void HashKeysNotKeyTest()
{
RedisValue[] keys = hashStudy.HashKeys(defaultHashKey);
Assert.NotNull(keys);
Assert.Empty(keys);
}
/// <summary>
/// 获取哈希所有字段的Key
/// </summary>
[Fact]
public void HashKeys()
{
AddDefaultStudent();
RedisValue[] keys = hashStudy.HashKeys(defaultHashKey);
Assert.NotEmpty(keys);
Assert.Contains("Id", keys);
Assert.Contains("Name", keys);
Assert.Contains("Age", keys);
}
#endregion
#region HashValues
/// <summary>
/// 哈希不存在时获取所有字段的Key
/// </summary>
[Fact]
public void HashValuesNotKeyTest()
{
RedisValue[] keys = hashStudy.HashValues(defaultHashKey);
Assert.NotNull(keys);
Assert.Empty(keys);
}
/// <summary>
/// 获取哈希所有字段的Key
/// </summary>
[Fact]
public void HashValues()
{
AddDefaultStudent();
RedisValue[] values = hashStudy.HashValues(defaultHashKey);
Assert.NotEmpty(values);
Assert.Contains(defaultStudent.Id, values);
Assert.Contains(defaultStudent.Name, values);
Assert.Contains(defaultStudent.Age, values);
}
#endregion
#region HashLength
/// <summary>
/// 哈希不存在时,获取字段数
/// </summary>
[Fact]
public void HashLengthNotKeyTest()
{
string redisKey = preHashKey + defaultStudent.Id;
var result = hashStudy.HashLength(redisKey);
Assert.Equal(0, result);
}
/// <summary>
/// 获取哈希字段数
/// </summary>
[Fact]
public void HashLengthTest()
{
string redisKey = preHashKey + defaultStudent.Id;
AddDefaultStudent();
var result = hashStudy.HashLength(redisKey);
Assert.Equal(3, result);
}
#endregion
#region HashScan
/// <summary>
/// 哈希不存在时HashScan
/// </summary>
[Fact]
public void HashScanNotKey()
{
var hashEntrys= hashStudy.HashScan(defaultHashKey);
var num = hashEntrys.Count();
Assert.Equal(0, num);
var entryList = hashEntrys.ToList();
Assert.Empty(entryList);
}
#endregion
#region HashExists
/// <summary>
/// 指定字段是否存在
/// </summary>
[Fact]
public void HashExists()
{
string redisKey = preHashKey + defaultStudent.Id;
var studentEntries = new HashEntry[]
{
new HashEntry("Id",1),
new HashEntry("Name",defaultStudent.Name),
};
//插入Sudent
var addHash = hashStudy.HashSet(redisKey, studentEntries);
Assert.True(addHash);
Assert.True(hashStudy.HashExists(redisKey, "Id"));
Assert.True(hashStudy.HashExists(redisKey, "Name"));
Assert.False(hashStudy.HashExists(redisKey, "Age"));
}
#endregion
#region HashDelete
/// <summary>
/// 哈希不存在时,删除哈希字段
/// </summary>
[Fact]
public void HashDeleteNotKeyTest()
{
string redisKey = preHashKey + defaultStudent.Id;
var hashDeleteResult = hashStudy.HashDelete(redisKey, "FieldFirst");
Assert.False(hashDeleteResult);
}
/// <summary>
/// 删除不存在的哈希字段
/// </summary>
[Fact]
public void HashDeleteNotFieldTest()
{
string redisKey = preHashKey + defaultStudent.Id;
hashStudy.HashIncrement(redisKey, "Id",1);
var hashDeleteResult = hashStudy.HashDelete(redisKey, "Name");
Assert.False(hashDeleteResult);
}
/// <summary>
/// 删除哈希字段
/// </summary>
[Fact]
public void HashDeleteTest()
{
string redisKey = preHashKey + defaultStudent.Id;
AddDefaultStudent();
var hashDeleteResult = hashStudy.HashDelete(redisKey, "Id");
Assert.True(hashDeleteResult);
hashDeleteResult = hashStudy.HashDelete(redisKey, "Name");
Assert.True(hashDeleteResult);
hashDeleteResult = hashStudy.HashDelete(redisKey, "Age");
Assert.True(hashDeleteResult);
}
#endregion
#region HashKeyDelete
/// <summary>
/// 删除学生
/// </summary>
[Fact]
public void KeyDeleteTest()
{
Assert.False(redisDatabase.KeyDelete(preHashKey + "-2000"));
}
#endregion
/// <summary>
/// 清理
/// </summary>
public void Dispose()
{
DeleteExitsStudents();
}
#region 辅助方法
/// <summary>
/// 删除Redis中的测试学生
/// </summary>
private void DeleteExitsStudents()
{
if (defaultStudent != null)
{
redisDatabase.KeyDelete(preHashKey + defaultStudent.Id);
}
}
private void AddDefaultStudent()
{
string redisKey = preHashKey + defaultStudent.Id;
var studentEntries = new HashEntry[]
{
new HashEntry("Id",1),
new HashEntry("Name",defaultStudent.Name),
new HashEntry("Age",defaultStudent.Age),
};
//插入Sudent
var addHash = hashStudy.HashSet(redisKey, studentEntries);
}
#endregion
}
}