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 { /// /// Redis Hash 类型测试 /// public class RedisHashStudyTest : IDisposable { #region 初始化 private readonly ITestOutputHelper testOutput; private IDatabase redisDatabase = null; private RedisHashStudy hashStudy = null; private List students; private Student defaultStudent = null; private string preHashKey = "RedisStudy:Student:"; private string defaultHashKey = ""; private int keyExpireSeconds = 20; /// /// 构造 /// 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() { 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 /// /// xUnit输出信息 测试 /// [Fact(DisplayName = "HashSet 输出信息测试")] public void HashSetOutputTest() { Assert.True(true); testOutput.WriteLine("我是xUnit测试输出信息"); } /// /// 参数异常 测试 /// [Fact(DisplayName = "HashSet 异常测试")] public void HashSetExceptionTest() { string redisKey = preHashKey + defaultStudent.Id; //参数异常测试 Assert.Throws(() => hashStudy.HashSet(string.Empty, null)); Assert.Throws(() => hashStudy.HashSet("", null)); Assert.Throws(() => hashStudy.HashSet(preHashKey + "-1", null)); Assert.Throws(() => hashStudy.HashSet(preHashKey + "-1", new HashEntry[] { })); } /// /// 参数 When 测试 /// [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); } /// /// 添加一个默认学生 测试 /// [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)); } /// /// 添加一组初始化设置的学生 测试 /// [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); } } /// /// 设置一个哈希字段 测试 /// [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)); } /// /// 设置一组哈希字段 测试 /// [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)); } /// /// 特例测试:给key为空的哈希 设置字段 /// 结 果:添加或更新操作能成功,但是字段值插入不进去。 /// [Fact] public void HashSetForEmptyKeyTest() { Assert.True(hashStudy.HashSet(string.Empty, "Name", "wanggaofeng")); redisDatabase.KeyDelete(string.Empty); } /// /// 特例测试:给字段名为空串的哈希 设置字段 /// 结 果:添加或更新操作正常,只是字段键名为"" /// [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 /// /// 字段值不是数字时,异常 /// 原注释:字段不为数据字,则改为数字 /// 实际执行:抛出异常,不知道是原注释错误,还是其它原因 /// [Fact] public void HashDecrementExceptionTest() { string redisKey = preHashKey + defaultStudent.Id; Assert.True(hashStudy.HashSet(redisKey, "Name", "wanggaofeng")); Assert.Throws(() => hashStudy.HashDecrement(redisKey, "Name", 1)); } /// /// 哈希表不存在 /// 则先创建哈希表,再添加值为0的字段,然后执行自减操作 /// [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")); } /// /// 自减字段不存在 /// 先添加字段,值设为0,然后执行自减操作 /// [Fact] public void HashDecrementHashFieldTest() { string redisKey = preHashKey + defaultStudent.Id; //字段不存在,则创建之 Assert.Equal(-1, hashStudy.HashDecrement(redisKey, "Age", 1)); Assert.Equal(-1, hashStudy.HashGet(redisKey, "Age")); } /// /// 自减负数,则自增 /// [Fact] public void HashDecrementMinusTest() { string redisKey = preHashKey + defaultStudent.Id; //自减负数时,则自增 Assert.Equal(2, hashStudy.HashDecrement(redisKey, "Age", -2)); } /// /// 自减整数 /// [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)); } /// /// 自减浮点数 /// 断言应该用精度值在一个小范围内 /// [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 /// /// 字段值不是数字时,异常 /// 原注释:字段不为数据字,则改为数字 /// 实际执行:抛出异常,不知道是原注释错误,还是其它原因 /// [Fact] public void HashIncrementExceptionTest() { string redisKey = preHashKey + defaultStudent.Id; Assert.True(hashStudy.HashSet(redisKey, "Name", "wanggaofeng")); Assert.Throws(() => hashStudy.HashIncrement(redisKey, "Name", 1)); } /// /// 哈希表不存在 /// 则先创建哈希表,再添加值为0的字段,然后执行自增操作 /// [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")); } /// /// 自增字段不存在 /// 先添加字段,值设为0,然后执行自增操作 /// [Fact] public void HashIncrementHashFieldTest() { string redisKey = preHashKey + defaultStudent.Id; //字段不存在,则创建之 Assert.Equal(1, hashStudy.HashIncrement(redisKey, "Age", 1)); Assert.Equal(1, hashStudy.HashGet(redisKey, "Age")); } /// /// 自增负数,则自减 /// [Fact] public void HashIncrementMinusTest() { string redisKey = preHashKey + defaultStudent.Id; //自增负数时,则自减 Assert.Equal(-2, hashStudy.HashIncrement(redisKey, "Age", -2)); } /// /// 自增整数 /// [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)); } /// /// 自增浮点数 /// 断言应该用精度值在一个小范围内 /// [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 /// /// 获取一个学生 /// [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 /// /// 哈希表不存在时,获取字段值 /// [Fact] public void HashGetNotKkeyTest() { string redisKey = preHashKey + defaultStudent.Id; var result = hashStudy.HashGet(redisKey, "Id"); Assert.False(result.HasValue); } /// /// 字段不存在时,获取字段值 /// [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 /// /// 哈希不存在时,获取所有字段的Key /// [Fact] public void HashKeysNotKeyTest() { RedisValue[] keys = hashStudy.HashKeys(defaultHashKey); Assert.NotNull(keys); Assert.Empty(keys); } /// /// 获取哈希所有字段的Key /// [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 /// /// 哈希不存在时,获取所有字段的Key /// [Fact] public void HashValuesNotKeyTest() { RedisValue[] keys = hashStudy.HashValues(defaultHashKey); Assert.NotNull(keys); Assert.Empty(keys); } /// /// 获取哈希所有字段的Key /// [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 /// /// 哈希不存在时,获取字段数 /// [Fact] public void HashLengthNotKeyTest() { string redisKey = preHashKey + defaultStudent.Id; var result = hashStudy.HashLength(redisKey); Assert.Equal(0, result); } /// /// 获取哈希字段数 /// [Fact] public void HashLengthTest() { string redisKey = preHashKey + defaultStudent.Id; AddDefaultStudent(); var result = hashStudy.HashLength(redisKey); Assert.Equal(3, result); } #endregion #region HashScan /// /// 哈希不存在时,HashScan /// [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 /// /// 指定字段是否存在 /// [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 /// /// 哈希不存在时,删除哈希字段 /// [Fact] public void HashDeleteNotKeyTest() { string redisKey = preHashKey + defaultStudent.Id; var hashDeleteResult = hashStudy.HashDelete(redisKey, "FieldFirst"); Assert.False(hashDeleteResult); } /// /// 删除不存在的哈希字段 /// [Fact] public void HashDeleteNotFieldTest() { string redisKey = preHashKey + defaultStudent.Id; hashStudy.HashIncrement(redisKey, "Id",1); var hashDeleteResult = hashStudy.HashDelete(redisKey, "Name"); Assert.False(hashDeleteResult); } /// /// 删除哈希字段 /// [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 /// /// 删除学生 /// [Fact] public void KeyDeleteTest() { Assert.False(redisDatabase.KeyDelete(preHashKey + "-2000")); } #endregion /// /// 清理 /// public void Dispose() { DeleteExitsStudents(); } #region 辅助方法 /// /// 删除Redis中的测试学生 /// 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 } }