TDD Tip:方法内部New出来的对象如何Mock
来源:互联网 发布:光翼网络班视频 编辑:程序博客网 时间:2024/05/21 07:55
--内容摘要:解决的问题:方法内部new的对象在测试时希望能够用mock对象去代替。问题:以下方法可以解决,但是很是丑陋,各位大侠是否有更好的方法?描述:如果说把内部的方法放到类的一个公开成员变量,或者放到方法的参数里,我的意见是公开了不应该公开的东西。使用第三方的类库: Mock工具 Rhino.Mocks, IOC: Castle.Windsor1. 现在我又这么一段代码,我想测试Math内部这两个方法&n。。。
转 http://www.pin5i.com/showtopic-21589.html
解决的问题:方法内部new的对象在测试时希望能够用mock对象去代替。
问题:以下方法可以解决,但是很是丑陋,各位大侠是否有更好的方法?
描述:如果说把内部的方法放到类的一个公开成员变量,或者放到方法的参数里,我的意见是公开了不应该公开的东西。
使用第三方的类库: Mock工具 Rhino.Mocks, IOC: Castle.Windsor
1. 现在我又这么一段代码,我想测试Math内部这两个方法
- public class Math
- {
- public long MathAdd(int a, int b)
- {
- Calc c = new Calc();
- return c.Add(a, b);
- }
- public long MathAdd2Price(int a)
- {
- Calc c = new Calc();
- return c.AddCount(a) + c.count;
- }
- }
- public class Calc
- {
- public int count = 0;
- public long Add(int a, int b)
- {
- return a + b;
- }
- public long AddCount(int num)
- {
- return count + num;
- }
- }
2. 我们看到,由于是在内部new的对象,我们就对Calc类产生了很大的依赖,于是我想到注入一个对像,下面是我的设计
- public class ContainerFactory
- {
- public static IWindsorContainer container;
- public bool IsDebug = false;
- private static readonly ContainerFactory instance = new ContainerFactory();
- public static ContainerFactory Instance
- {
- get
- {
- return instance;
- }
- }
- private ContainerFactory()
- {
- AddAllCompent();
- }
- private void AddAllCompent()
- {
- if (container == null)
- {
- container = new WindsorContainer();
- //此处职位演示,未使用接口
- container.AddComponentWithLifestyle<Calc>("Calc", LifestyleType.Transient); }
- }
- }
这样我们的Math类可改成这样
- public class Math
- {
- public long MathAdd(int a, int b)
- {
- // Calc c = new Calc();
- Calc c =(Calc) ContainerFactory.container["Calc"];
- return c.Add(a, b);
- }
- public long MathAdd2Price(int a)
- {
- Calc c = (Calc)ContainerFactory.container["Calc"];
- return c.AddCount(a) + c.count;
- }
- }
3. 但是,我们如何在测试中用我们Mock的对象代替真实的对象呢?下面是我想的一个自己也认为不好的方法,但能凑活着用
- public class ContainerFactory
- {
- private IWindsorContainer container;
- public bool IsDebug = false;
- private static readonly ContainerFactory instance = new ContainerFactory();
- public static ContainerFactory Instance
- {
- get
- {
- return instance;
- }
- }
- private ContainerFactory()
- {
- AddAllCompent();
- }
- private void AddAllCompent()
- {
- if (container == null)
- {
- container = new WindsorContainer();
- //此处职位演示,未使用接口
- container.AddComponentWithLifestyle<Calc>("Calc", LifestyleType.Transient); }
- }
- #region Calc
- private Calc DebugCalc;
- public Calc Calc
- {
- get
- {
- if (IsDebug && DebugCalc != null)
- {
- return DebugCalc;
- }
- else
- {
- return (Calc)container["Calc"];
- }
- }
- set
- {
- // just for test, for mock object
- if (IsDebug)
- {
- DebugCalc = value;
- }
- else
- {
- throw new Exception("just for test");
- }
- }
- }
- #endregion
- }
修改我们的类
- public class Math
- {
- public long MathAdd(int a, int b)
- {
- // Calc c = new Calc();
- Calc c = ContainerFactory.Instance.Calc;
- return c.Add(a, b);
- }
- public long MathAdd2Price(int a)
- {
- Calc c = ContainerFactory.Instance.Calc;
- return c.AddCount(a) + c.count;
- }
- }
这样我们来看我们通过了测试的代码
- [TestClass()]
- public class MathTest
- {
- [TestMethod()]
- public void MathAddTest()
- {
- Math m = new Math();
- // 想让真实代码内部,使用的是Mock的对象
- // Arrange
- MockRepository mocks = new MockRepository();
- Calc mockCalc = mocks.Stub<Calc>();
- mockCalc.count = 5;
- ContainerFactory.Instance.IsDebug = true; //这句很重要
- ContainerFactory.Instance.Calc = mockCalc;
- mocks.ReplayAll();
- // Act
- Assert.AreEqual(m.MathAdd(5, 5), 10);
- Assert.AreEqual(mockCalc.AddCount(6), 11);
- mocks.VerifyAll();
- Calc mockCalc2 = mocks.Stub<Calc>();
- mocks.ReplayAll();
- // 这里有问题,我们希望他是7,但实际是12,因为需要测试中的和实际代码用同一个对象,
- // 他保留上次的状态count的值5
- Assert.AreEqual(mockCalc.AddCount(7), 12);
- mocks.VerifyAll();
- }
- [TestMethod]
- public void MathAddTestActual()
- {
- //这里测试实际使用代码,没用Mock
- Math m = new Math();
- Assert.AreEqual(m.MathAdd(5,6), 11);
- Assert.AreEqual(m.MathAdd2Price(9), 9);
- Calc c = ContainerFactory.Instance.Calc;
- Assert.AreEqual(c.AddCount(5), 5);
- c.count = 20;
- Assert.AreEqual(c.AddCount(5), 25);
- Calc d = ContainerFactory.Instance.Calc;
- Assert.AreEqual(d.AddCount(30), 30);
- Assert.AreEqual(c.count, 20);
- Assert.AreEqual(d.count, 0);
- }
- }
总结:这样可以不使用用public的类成员变量,不用通过方法参数注入注入对象
问题: ContainerFactory代码较多,测试时需要设标志。
- TDD Tip:方法内部New出来的对象如何Mock
- 使用工厂方法mock测试方法体内中new出来的对象
- new出来的对象一定要delete
- cocos2d-x-3.5 中new 出来的对象大部分是如何处理的
- 如何写Fake和Mock的方法
- 阻止类被new出来的方法
- 关于 Spring new出来的对象 与自动注入对象
- jmockit mock 方法内创建对象的方法调用
- PHP中new出来的对象和 clone复制出来的对象
- Item 17 将new出来的对象存入智能指针
- Item 13 管理在堆上new出来的对象
- C++箴言:将new出来的对象存入智能指针
- Mockito 中捕获 mock 对象方法的调用参数
- JMockit 中捕获 mock 对象方法的调用参数
- 如何delete vector中new出来的内存
- Mockito 如何 mock 返回值为 void 的方法
- Mockito 如何 mock 返回值为 void 的方法
- 单元测试时的new InitialContext() mock
- error C2041: illegal digit '9' for base '8'
- 利用SQLiteOpenHelper来管理SQLite数据库
- cas入门文章
- I/O
- 1
- TDD Tip:方法内部New出来的对象如何Mock
- windows编程中画笔与画刷
- Nginx 访问控制
- 自卑一阵子
- 嵌入式Linux下基于FFmpeg的视频硬件编解码
- GeoServer+OpenLayers发布下载的Google卫星影像
- Axis-1.1 webService实现跨project传递参数入
- 一个游戏程序员的学习资料
- 在vs2010+MFC中动态添加菜单选项