都说测试驱动开发,但是想写好单元测试其实不容易,不是因为测试用例难以构造,而是因为很多时候方法非常复杂

其中部分测试想要完成就十分费力,其中让人崩溃的地方主要如下:

  • 实例私有函数
  • 实例静态私有函数
  • 十分难以构造的对象

实例私有函数

继承重写

可以通过反射来进行测试,但是想想你写的代码才200行,测试的代码1000行,就让你很崩溃

之前我主要是把这个方法写成protected 然后通过在测试代码中写子类来进行测试。

但是事实上这已经破坏了封装,而且很多时候,为了能够写出测试,不得不改变API的设计,将一些私有实例变量都扔到了参数里面,方便自己写测试。


// 原来的类 public class A{
private SomeType someType; private SomeType someMethod(); } // 通过改变原来的类的限制,将其改为protected public class A {
protected SomeType someType; protected SomeType someMethod(); } // 尤其是当测试的函数可能只是改变对象状态的void方法的时候,为了验证对象状态的改变,就必须使用protected限制符
// 通过这种方法进行测试其实比较麻烦,而且还破坏了原来的设计
class TestClass : A {
public SomeType testSomeMethod() {
return base.someMethod();
}
}

不过,当用来测试部分的本来就是用来继承的类的时候,这个方法还算可以

当然还有一个很方便的方法,就是使用PrivateObject

PrivateObject

// 比如这个类内部的私有方法

public class Calculate

    private int Add(int a, int b)
{
return a + b;
}
} // 可以通过微软UT框架自带的PrivateObject来完成,没看源码,不过看到Invoke,估计也是使用反射写的 [TestMethod]
public void TestPrivateAdd()
{
PrivateObject po = new PrivateObject(new Calculate()); Assert.AreEqual(po.Invoke("Add", 1, 2), 3);
}

私有静态方法

当然了,碰到实例方法可以使用继承测试,但是碰到了静态方法,本人立刻就没有办法了,所以Google了一下

发现了微软的PrivateType对象

PrivateType

比较类似于PrivateObject

public class Calculate
{
internal static int AddStatic(int a, int b)
{
return a + b;
}
} // 可以通过PrivateType的 InvokeStatic来调用静态方法
[TestMethod]
public void TestInternalStaticAdd()
{
PrivateType po = new PrivateType(typeof(Calculate)); Assert.AreEqual(po.InvokeStatic("AddStatic", 1, 2), 3);
}

难以构造的对象

最简单的例子,你测试一个网络请求的时候,构造一个request就让人吐血

当做一个复杂系统的时候,哪怕你只调用一个复杂结构的部分对象,但是因为对象的复杂,你可能就需要阅读超多的API

所以就有了Mock框架,本文使用的Mock框架是Moq的mock对象,用起来还算简单

感觉很有元编程的感觉

// 之前测试的时候因为读取数据库的对象是一个IDataReader
// 看到这个接口我完全不知道怎么构造,该使用哪一个子类来构造,但是有了Mock就不同了 [TestMethod()]
public void FillRuleTest()
{
// 通过mock来构造复杂对象,其中IDataReader是我需要构造的对象
Mock<IDataReader> mock = new Mock<IDataReader>();
mock.Setup(m => m["abc"]).Returns("abc"); // 构造完成后,可以通过mock.Object来获取对应构造的对象
IDataReader mockObj = mock.Object;
Assert.AreEqual(mockObj["abc"].ToString(), "abc"); // 现在构造参数就会容易很多,你写的Returns也能返回你想要的值
}

最新文章

  1. (转)Unity AssetBundle爬坑手记
  2. [转]RabbitMQ消息队列在PHP下的应用
  3. spring mvc设置字符集过滤器
  4. 错误记录 git pull
  5. Storm系列(十五)架构分析之Executor-Spout
  6. 基于bootstrap的轮播广告页,带图片和文字
  7. UIDocumentInteractionController 文件预览
  8. mysql安装出现问题(The service already exists)
  9. centos 7.5安装docker-CE 18
  10. 移动端使用mint-ui loadmore实现下拉刷新上拉显示更多
  11. 汇编语言--微机CPU的指令系统(五)(数据传送指令)
  12. ThinkPHP框架 做个简单表单 添加数据例子__ACTION__ __SELF__
  13. IIS编辑器错误信息:CS0016解决方案
  14. python--第三天总结
  15. vue+axios自己踩过的坑
  16. 深入理解java虚拟机---java内存区域与内存溢出异常---2堆栈溢出
  17. Redis简介和常见的面试题
  18. ubuntu16.04 关闭防火墙的方法
  19. SpringCloud学习笔记(一)——基础
  20. flask框架的学习

热门文章

  1. update_notifier 造成nodejs进程数量增长的问题
  2. hdu oj 3371 Connect the Cities (最小生成树)
  3. 从零開始学Xamarin.Forms(二) 环境搭建、创建项目
  4. Codeforces--630N--Forecast(方程求解)
  5. Java-java-com-util-common-service:CrudService.java
  6. 利用存储过程插入50W+数据
  7. 原生JS---8
  8. HTML+CSS+JS总结
  9. [Luogu 2216] [HAOI2007]理想的正方形
  10. 猜拳游戏项目(涉及知识点Scanner、Random、For、数组、Break、Continue等)