博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简易扩展Visual Studio UnitTesting支持TestMethodCase
阅读量:5828 次
发布时间:2019-06-18

本文共 6531 字,大约阅读时间需要 21 分钟。

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 < 0)            throw new ArgumentOutOfRangeException("n");        return name.Length / n;    }}
[TestClass]public class MyClassTest{    [TestMethod]    public void DoWork()    {        var name = "test";        var n = 5;        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 = 5;        var myClass = new MyClass();        myClass.DoWork(null, n);    }    [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]    public void DoWork_NameIsEmpty()    {        var n = 5;        var myClass = new MyClass();        myClass.DoWork(String.Empty, n);    }    [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]    public void DoWork_NameIsWhiteSpace()    {        var n = 5;        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, -1);    }}

可以发现为了测试参数输入验证是否达到预期的效果,额外编写了4个测试用例。如果使用NUnit的TestCase可以简化如下:

[TestFixture]public class MyClassTest{    [TestCase("Test", 5)]    [TestCase(null, 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestCase("", 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestCase(" ", 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestCase("Test", -1, 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的文章。不过我选择了更为简单的在原有的用例中扩展一个TestMethodCaseAttribute,例如:

[TestClass]public class MyClassTest{    [TestMethod]    [TestMethodCase("Test", 5)]    [TestMethodCase(null, 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestMethodCase("", 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestMethodCase(" ", 5, ExpectedException = typeof(ArgumentOutOfRangeException))]    [TestMethodCase("Test", -1, ExpectedException = typeof(ArgumentOutOfRangeException))]    public void DoWork()    {        TestMethodCaseHelper.Run(context =>         {            var name = context.GetArgument
(0); var n = context.GetArgument
(1); 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
body) { var testMethodCases = FindTestMethodCaseByCallingContext(); foreach (var testMethodCase in testMethodCases) RunTest(testMethodCase, body); } internal static IEnumerable
FindTestMethodCaseByCallingContext() { var stackFrames = StackFrameHelper.GetCurrentCallStack(); var forTestFrame = stackFrames.FirstOrDefault(p => GetTestMethodCaseAttributes(p).Any()); return forTestFrame != null ? GetTestMethodCaseAttributes(forTestFrame) : new TestMethodCaseAttribute[0]; } private static IEnumerable
GetTestMethodCaseAttributes(StackFrame stackFrame) { return GetTestMethodCaseAttributes(stackFrame.GetMethod()); } private static IEnumerable
GetTestMethodCaseAttributes(MethodBase method) { return method.GetCustomAttributes(typeof(TestMethodCaseAttribute), true).OfType
(); } private static void RunTest(TestMethodCaseAttribute testMethodCase, Action
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
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
(Int32 index) { return (T)_testMethodCase.Arguments.ElementAtOrDefault(index); }}
internal static class StackFrameHelper{    public static IEnumerable
GetCurrentCallStack() { var frameIndex = 0; while (true) { var stackFrame = new StackFrame(frameIndex, false); if (stackFrame.GetILOffset() == StackFrame.OFFSET_UNKNOWN) break; yield return stackFrame; ++frameIndex; } }}

 

转载地址:http://ppadx.baihongyu.com/

你可能感兴趣的文章
CSS3
查看>>
ul下的li浮动,如何是ul有li的高度
查看>>
C++ primer plus
查看>>
python mysqlDB
查看>>
UVALive 3942 Remember the Word Tire+DP
查看>>
从微软的DBML文件中我们能学到什么(它告诉了我们什么是微软的重中之重)~目录...
查看>>
被需求搞的一塌糊涂,怎么办?
查看>>
c_数据结构_队的实现
查看>>
jquery 选择器总结
查看>>
Qt设置背景图片
查看>>
【阿里云文档】常用文档整理
查看>>
java中的Volatile关键字
查看>>
前端自定义图标
查看>>
Vagrant的一个BUG - 不支持'change_host_name'
查看>>
实验二
查看>>
独立开发一个云(PaaS)的核心要素, Go, Go, Go!!!
查看>>
MyBatis使用DEMO及cache的使用心得
查看>>
网站文章如何能自动判定是抄袭?一种算法和实践架构剖析
查看>>
【OpenCV学习】滚动条
查看>>
ofo用科技引领行业进入4.0时代 用户粘性连续8个月远甩摩拜
查看>>