简易扩展Visual Studio UnitTesting支持TestMethodCase
NUnit的TestCaseAttribute可以简化大量的测试参数输入用例的编写,如果基于Visual Studio Unit Test Project开发则默认没有类似的功能,看一段对比代码:
public class MyClass
{
public Int32 DoWork(String name, Int32 n)
{
if (String.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException("name"); if (n < )
throw new ArgumentOutOfRangeException("n"); return name.Length / n;
}
}
[TestClass]
public class MyClassTest
{
[TestMethod]
public void DoWork()
{
var name = "test";
var n = ; var myClass = new MyClass();
var result = myClass.DoWork(name, n); Assert.IsTrue(result == name.Length / n);
} [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void DoWork_NameIsNull()
{
var n = ; var myClass = new MyClass();
myClass.DoWork(null, n);
} [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void DoWork_NameIsEmpty()
{
var n = ; var myClass = new MyClass();
myClass.DoWork(String.Empty, n);
} [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void DoWork_NameIsWhiteSpace()
{
var n = ; var myClass = new MyClass();
myClass.DoWork(" ", n);
} [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void DoWork_NLessThanZero()
{
var name = "test"; var myClass = new MyClass();
myClass.DoWork(name, -);
}
}
可以发现为了测试参数输入验证是否达到预期的效果,额外编写了4个测试用例。如果使用NUnit的TestCase可以简化如下:
[TestFixture]
public class MyClassTest
{
[TestCase("Test", )]
[TestCase(null, , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestCase("", , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestCase(" ", , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestCase("Test", -, ExpectedException = typeof(ArgumentOutOfRangeException))]
public void DoWork(String name, Int32 n)
{
var myClass = new MyClass();
var result = myClass.DoWork(name, n); Assert.IsTrue(result == name.Length / n);
}
}
要让Visual Studio Test支持类似的方式可以自己扩展,参考Visual Studio Team Test的Extending the Visual Studio Unit Test Type文章。不过我选择了更为简单的在原有的用例中扩展一个TestMethodCaseAttribute,例如:
[TestClass]
public class MyClassTest
{
[TestMethod]
[TestMethodCase("Test", )]
[TestMethodCase(null, , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestMethodCase("", , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestMethodCase(" ", , ExpectedException = typeof(ArgumentOutOfRangeException))]
[TestMethodCase("Test", -, ExpectedException = typeof(ArgumentOutOfRangeException))]
public void DoWork()
{
TestMethodCaseHelper.Run(context =>
{
var name = context.GetArgument<String>();
var n = context.GetArgument<Int32>(); var myClass = new MyClass();
var result = myClass.DoWork(name, n); Assert.IsTrue(result == name.Length / n);
});
}
}
只要有一个TestMethodCase未通过,当前的TestMethod既为失败。使用这种方式进行Code Coverage统计并不受影响,可以正确评估
public static class TestMethodCaseHelper
{
public static void Run(Action<TestMethodCaseContext> body)
{
var testMethodCases = FindTestMethodCaseByCallingContext(); foreach (var testMethodCase in testMethodCases)
RunTest(testMethodCase, body);
} internal static IEnumerable<TestMethodCaseAttribute> FindTestMethodCaseByCallingContext()
{
var stackFrames = StackFrameHelper.GetCurrentCallStack();
var forTestFrame = stackFrames.FirstOrDefault(p => GetTestMethodCaseAttributes(p).Any()); return forTestFrame != null ? GetTestMethodCaseAttributes(forTestFrame) : new TestMethodCaseAttribute[];
} private static IEnumerable<TestMethodCaseAttribute> GetTestMethodCaseAttributes(StackFrame stackFrame)
{
return GetTestMethodCaseAttributes(stackFrame.GetMethod());
} private static IEnumerable<TestMethodCaseAttribute> GetTestMethodCaseAttributes(MethodBase method)
{
return method.GetCustomAttributes(typeof(TestMethodCaseAttribute), true).OfType<TestMethodCaseAttribute>();
} private static void RunTest(TestMethodCaseAttribute testMethodCase, Action<TestMethodCaseContext> body)
{
TestSettings.Output.WriteLine("Run TestMethodCase {0} started", testMethodCase.Name);
var stopwatch = Stopwatch.StartNew();
RunTestCore(testMethodCase, body);
stopwatch.Stop();
TestSettings.Output.WriteLine("Run TestMethodCase {0} finished({1})", testMethodCase.Name, stopwatch.ElapsedMilliseconds);
} private static void RunTestCore(TestMethodCaseAttribute testMethodCase, Action<TestMethodCaseContext> body)
{
var testContext = new TestMethodCaseContext(testMethodCase); if (testMethodCase.ExpectedException != null)
RunTestWithExpectedException(testMethodCase.ExpectedException, () => body(testContext));
else
body(testContext);
} private static void RunTestWithExpectedException(Type expectedExceptionType, Action body)
{
try
{
body();
}
catch (Exception ex)
{
if (ex.GetType() == expectedExceptionType)
return; throw;
}
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class TestMethodCaseAttribute : Attribute
{
public TestMethodCaseAttribute(params Object[] arguments)
{
this.Arguments = arguments;
} public String Name { get; set; } public Type ExpectedException { get; set; } public Object[] Arguments { get; private set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class TestMethodCaseAttribute : Attribute
{
public TestMethodCaseAttribute(params Object[] arguments)
{
this.Arguments = arguments;
} public String Name { get; set; } public Type ExpectedException { get; set; } public Object[] Arguments { get; private set; }
}
public class TestMethodCaseContext
{
private readonly TestMethodCaseAttribute _testMethodCase; internal TestMethodCaseContext(TestMethodCaseAttribute testMethodCase)
{
_testMethodCase = testMethodCase;
} public T GetArgument<T>(Int32 index)
{
return (T)_testMethodCase.Arguments.ElementAtOrDefault(index);
}
}
internal static class StackFrameHelper
{
public static IEnumerable<StackFrame> GetCurrentCallStack()
{
var frameIndex = ; while (true)
{
var stackFrame = new StackFrame(frameIndex, false); if (stackFrame.GetILOffset() == StackFrame.OFFSET_UNKNOWN)
break; yield return stackFrame; ++frameIndex;
}
}
}
简易扩展Visual Studio UnitTesting支持TestMethodCase的更多相关文章
- 如何扩展 Visual Studio 编辑器
在 Visual Studio 2010 的时代,扩展 Visual Studio 的途径有很多,开发者可以选择宏.Add-in.MEF 和 VSPackages 进行自定义的扩展.但是宏在 Visu ...
- VS2015提示:未安装Style的Visual Studio语言支持,代码编辑Intellisense将不可用。服务器控件的标记Intellisense可能不起作用
一.问题 最近在VS2015打开文件,提示未安装Style的Visual Studio语言支持,代码编辑Intellisense将不可用.服务器控件的标记Intellisense可能不起作用. Int ...
- 让Visual Studio x64 支持 __asm内联汇编
目录 让Visual Studio x64 支持 __asm内联汇编 Intel Parallel Studio XE 2016安装 设置Interl C++ Compiler 使VS x64支持内联 ...
- 分享:扩展Visual Studio 的简单方法
作为 MS 阵营的码农,相信Visual Studio 肯定是大家的主要武器了,但不知道大家有没有扩展Visual Studio 的需求. 最近我需要做一个工具,发现最好是实现在VS里面,于是,Goo ...
- .NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器
.NET 开源了,Visual Studio 开始支持 Android 和 iOS 程序编写并自带 Android 模拟器 北京时间今天凌晨的 Connect(); 大会上,多少程序员的假想成为现实. ...
- 简介Gulp, Grunt, Bower, 和 Npm 对Visual Studio的支持
[原文发表地址]Introducing Gulp, Grunt, Bower, and npm support for Visual Studio Web 开发,特别是前端 Web 开发,正迅速变得像 ...
- [转]简介Gulp, Grunt, Bower, 和 Npm 对Visual Studio的支持
本文转自:http://www.cnblogs.com/whitewolf/p/4009199.html [原文发表地址]Introducing Gulp, Grunt, Bower, and npm ...
- Visual Studio 2013支持Xamarin的解决方案
转自博客园[遗忘的代码] Xamarin的Visual Studio插件目前还不支持VS 2013,所以需要在安装Xamarin的VS插件时把2010和2012全选上 (由于我的电脑里只剩2013,而 ...
- Visual Studio 2013 支持MVC3不完善,Razor智能提示不完整或者不提示
以下只是针对MVC3. 前天试用Orchard 1.8,用VS2013新建C#类库项目(ClassLibrary project),然后新建Views文件夹,新建cshtml,然后引用MVC3的相关d ...
随机推荐
- mysql 5.1超过默认8小时空闲时间解决办法(错误:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure)
报错: MySQL第二天早上第一次连接超时报错, com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications lin ...
- wine for MacOS
Installing Wine on Mac This tutorial is for intermediate users who want to install and use Wine on t ...
- fopen flock fclose 文件用法
fopen函数是用来打开文件或者连接 若成功,则返回 true.若失败,则返回 false. fopen打开连接是不能直接输出的 使用: <?php $file = fopen("te ...
- (IRCNN)Learning Deep CNN Denoiser Prior for Image Restoration-Kai Zhang
学习深度CNN去噪先验用于图像恢复(Learning Deep CNN Denoiser Prior for Image Restoration)-Kai Zhang 代码:https://githu ...
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
https://www.cnblogs.com/alexyuyu/articles/3454907.html
- free命令的具体含义
https://www.cnblogs.com/thinkam/p/8407043.html https://blog.csdn.net/andy205214/article/details/7709 ...
- [Bayes ML] This is Bayesian Machine Learning
From: http://www.cnblogs.com/bayesianML/p/6377588.html#central_problem You can do it: Dirichlet Proc ...
- jquery组件WebUploader文件上传用法详解
这篇文章主要为大家详细介绍了jquery组件WebUploader文件上传用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 WebUploader是由Baidu WebFE(FEX)团队开发的一 ...
- PMP考试相关
知识点:http://www.cnblogs.com/allenblogs/tag/PMbook/ 读书笔记: http://www.cnblogs.com/lensin/category/45538 ...
- LeetCode_Maximum Subarray | Maximum Product Subarray
Maximum Subarray 一.题目描写叙述 就是求一个数组的最大子序列 二.思路及代码 首先我们想到暴力破解 public class Solution { public int maxSub ...