public class LockTest
{
private IDatabase _database;
private readonly Random _random = new Random();
private int _num = 0; [SetUp]
public void SetUp()
{
_num = 0; //信号量,同时访问的线程1
var slim = new SemaphoreSlim(1, 1); //mock redis的接口
_database = Substitute.For<IDatabase>(); //mock LockTake 同时只有一个线程可以拿到锁
//slim.WaitAsync 参数为0时标识直接返回是否拿到锁,不会类似lock阻塞直至其他人释放
//这里主要mock redis的场景,拿不到要使用循环重复尝试拿锁,因此传0
//普通异步锁场景根据需求选择等待时间,使用等待时间理论上使用响应时间应比自己写循环简单且有更好的性能
_database.LockTakeAsync(Arg.Any<RedisKey>(), Arg.Any<RedisValue>(), Arg.Any<TimeSpan>())
.Returns(async call => await slim.WaitAsync(call.ArgAt<TimeSpan>(2))); //mock LockRelease 释放锁
_database.LockReleaseAsync(Arg.Any<RedisKey>(), Arg.Any<RedisValue>()).Returns(call =>
{
slim.Release();
return true;
});
} /// <summary>
/// 使用锁的版本,_num值会按预期加至5
/// </summary>
/// <returns></returns>
[Test]
public async Task WithLockTest()
{
var tasks = Enumerable.Range(1, 5).Select(c => LockTestTaskInner("1", "1", TimeSpan.FromSeconds(0)));
await Task.WhenAll(tasks);
Assert.AreEqual(_num, 5);
} /// <summary>
/// 无锁版本,_num值会配其他线程覆盖
/// </summary>
/// <returns></returns>
[Test]
public async Task WithoutLockTestTask()
{
var tasks = Enumerable.Range(1, 5).Select(async c =>
{
var tmp = _num;
//模拟覆盖写
await Task.Delay(_random.Next(5));
_num = tmp + 1;
});
await Task.WhenAll(tasks);
Console.WriteLine(_num);
Assert.AreNotEqual(_num, 5);
} private async Task LockTestTaskInner(string key, string value, TimeSpan expiry)
{
var reTryGetLock = true;
while (reTryGetLock)
{
var taskLockSuccess = await _database.LockTakeAsync(key, value, expiry);
if (taskLockSuccess)
{
reTryGetLock = false;
try
{
var tmp = _num;
//模拟覆盖写
await Task.Delay(_random.Next(5));
_num = tmp + 1;
}
finally
{
await _database.LockReleaseAsync(key, value);
}
}
else
{
//证明LockTakeAsync不会阻塞
//Console.WriteLine("retry");
await Task.Delay(_random.Next(10));
}
} }

单元测试NUnit,mock组件NSubstitute,信号量SemaphoreSlim,异步lock等例子的更多相关文章

  1. Spring Boot单元测试(Mock)

    Spring Boot单元测试(Mock) Java个人学习心得 2017-08-12 16:07 Mock 单元测试的重要性就不多说了,我这边的工程一般都是Spring Boot+Mybatis(详 ...

  2. MVC文件上传04-使用客户端jQuery-File-Upload插件和服务端Backload组件实现多文件异步上传

    本篇使用客户端jQuery-File-Upload插件和服务端Badkload组件实现多文件异步上传.MVC文件上传相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证类型和大小  ...

  3. Java单元测试(Junit+Mock+代码覆盖率)---------转

    Java单元测试(Junit+Mock+代码覆盖率) 原文见此处 单元测试是编写测试代码,用来检测特定的.明确的.细颗粒的功能.单元测试并不一定保证程序功能是正确的,更不保证整体业务是准备的. 单元测 ...

  4. c# 异步调用简单例子(转载)

    首先来看一个简单的例子: 小明在烧水,等水烧开以后,将开水灌入热水瓶,然后开始整理家务 小文在烧水,在烧水的过程中整理家务,等水烧开以后,放下手中的家务活,将开水灌入热水瓶,然后继续整理家务 这也是日 ...

  5. 并发教程--JAVA5中 计数信号量(Counting Semaphore)例子

    并发教程--JAVA5中 计数信号量(COUNTING SEMAPHORE)例子 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java中的计数信息量(C ...

  6. NUnit+mock+moq单元测试

    [TestFixture] public class InstantBatchBuyTest { private string _mallAbc; private string _itemCode; ...

  7. 企业应用架构研究系列二十六:信号量SemaphoreSlim与Semaphore

    在进行多线程程序的开发和设计的过程中,不可避免的需要引入semaphore信号量这个组件,这是.net框架提供的一个对多线程计数互斥的方案,就是允许指定的线程个数访问特定的资源而增加的 一个" ...

  8. Python3的单元测试模块Mock与性能测试模块CProfile

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_92 我们知道写完了代码需要自己跑一跑进行测试,一个写好的程序如果连测试都没有就上到生产环境是不敢想象的,这么做的人不是太自信就是太 ...

  9. Python单元测试和Mock测试

    单元测试 测试可以保证你的代码在一系列给定条件下正常工作 测试允许人们确保对代码的改动不会破坏现有的功能 测试迫使人们在不寻常条件的情况下思考代码,这可能会揭示出逻辑错误 良好的测试要求模块化,解耦代 ...

随机推荐

  1. 学习Tomcat(七)之Spring内嵌Tomcat

    前面的文章中,我们介绍了Tomcat容器的关键组件和类加载器,但是现在的J2EE开发中更多的是使用SpringBoot内嵌的Tomcat容器,而不是单独安装Tomcat应用.那么Spring是怎么和T ...

  2. Java JDK的下载与安装!Java基础

    在了解什么是Java.Java 语言的特点以及学习方法之后,本节将介绍如何搭建编写 Java 程序所需要的开发环境--JDK,只有搭建了环境才能敲代码! 学Java的都知道,JDK 是一种用于构建在 ...

  3. SpringBoot下使用AspectJ(CTW)下不能注入SpringIOC容器中的Bean

    SpringBoot下使用AspectJ(CTW)下不能注入SpringIOC容器中的Bean 在SpringBoot中开发AspectJ时,使用CTW的方式来织入代码,由于采用这种形式,切面Bean ...

  4. kvm安装window系统及使用NFS动态迁移

    验证是否开启虚拟化 # grep -E 'svm|vmx' /proc/cpuinfo - vmx is for Intel processors - svm is for AMD processor ...

  5. Dapr + .NET Core实战(十四)虚拟机集群部署 mDNS + Consul

    前面我们说了在单机模式下和K8S集群下的Dapr实战,这次我们来看看如何在不使用K8S的情况下,在一个传统的虚拟机集群里来部署Dapr. 1.环境准备 我们准备两台centos7虚拟机 Dapr1:1 ...

  6. js--标签语法的使用

    前言 在日常开发中我们经常使用到递归.break.continue.return等语句改变程序运行的位置,其实,在 JavaScript 中还提供了标签语句,用于标记指定的代码块,便于跳转到指定的位置 ...

  7. 简单的 Go 入门教程

    Go(又称 Golang )是 Google 开发的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语言 Docker 和 Kubernetes 都是使用 Go 进行开发的,这几年 Go 越来 ...

  8. 不会SQL也能做数据分析?浅谈语义解析领域的机会与挑战

    笔者按: 在第5次AI TIME PhD Debate上,笔者邀请了部分国内外语义解析领域的杰出华人学者共话语义解析的过去,现状和未来.本博客为笔者根据视频讨论总结的干货整理.对原视频感兴趣的同学可以 ...

  9. 注解,@Qualifier+@Autowired 和 @Resource

    摘要: 项目中,对于AOP的使用,就是通过用注解来注入的. 更改之前的注解,是使用:@Qualifier+@Autowired   但是,通过这样注解,在项目启动阶段,需要自动扫描的过程是非常缓慢的, ...

  10. 记一次关于pdf 下载需求变更到 pdf 在线预览

    背景: 之前的需求是根据接口中提供的Blob数据实现PDF下载,已实现代码如下: 1 const url = window.URL.createObjectURL(newBlob([response. ...