单元测试:如何使用大量的基础对象和业务逻辑来测试方法 [英] Unit testing: how to test methods with a lot of underlying objects and business logic

查看:184
本文介绍了单元测试:如何使用大量的基础对象和业务逻辑来测试方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的是单元测试的新手,尽管我花了很多时间在研究上,但是我无法为我的情况找到合适的方法.

I am really new to unit testing, and I can't figure out the proper way to do it for my case, though I spent crazy amount of time on research.

我的代码库很大(约3年的工作),不幸的是,它们耦合得很厉害,难以测试,并且从未对它进行过任何单元测试.

My code base is huge (~3 years of work), very coupled unfortunately, hard to test and no unit testing has ever been done on it.

因此,例如,当尝试测试集合类ProductCollection(更具体地说是它的bool MoveElementAtIndex(Product productToMove, int newIndex))时,我遇到以下问题:

So for instance, when trying to test a collection class ProductCollection, more specifically, the bool MoveElementAtIndex(Product productToMove, int newIndex) of it, I am encountering the following problems:

  • 首先,我必须初始化此new ProductCollection()
  • 构造函数初始化另一个手工制作的类:new KeyedList<ID, Product>.我想不应在此构造函数中调用此函数,因为我没有测试KeyedList.
  • 接下来,我正在尝试向此ProductCollection添加3种产品.
  • 然后我首先创建这3个new Product().
  • 但是Product类的构造函数做了几件事
  • 它为新创建的产品this.ID = IDUtils.ComputeNewIDBasedOnTheMoonPhase()计算一个唯一的ID.我想我也不应该对此进行测试,因为这不是我的范围.在这样的深度上,我应该如何避免此类呼叫?
  • 相同的Product构造函数为此产品分配一些默认属性:this.Properties = new ProductProperties(folderPathToDefaultProperties).不应该通过我的简单FieldCollection.MoveElementAtIndex测试来调用它,对吧?
  • 假设我现在终于有了我的产品对象,而我正试图将它们添加到我的收藏中.
  • 但是ProductCollection.Add(MyProduct)检查基础KeyedList是否已经包含该产品.这也是我应该避免的与测试无关的业务逻辑.问题是如何?
  • 此外,在此Add方法中,引发了一些事件,通知系统几件事情(例如,将新产品添加到集合中).我认为这些都不应该被解雇.
  • 最后,当我添加产品时,我将调用所需的SUT:move elements方法.
  • 但是此方法的逻辑也超出了我的测试范围:它验证底层的KeyedList实际上包含这些字段,它调用KeyedList.Remove()KeyedList.Insert()作为其移动逻辑,并触发事件就像CollectionModified.
  • first I have to initialize this new ProductCollection()
  • the constructor initializes another hand made class: new KeyedList<ID, Product>. I suppose this should not be called within this constructor, since I'm not testing KeyedList.
  • next, I am trying to add 3 products to this ProductCollection.
  • I am then first creating these 3 new Product().
  • But the constructor of Product class does several things
  • It computes a unique ID for the newly created product: this.ID = IDUtils.ComputeNewIDBasedOnTheMoonPhase(). I suppose I should not test this neither, since it's not my scope. How should I avoid such calls at this level of deepness?
  • The same Product constructor assigns some default properties for this product: this.Properties = new ProductProperties(folderPathToDefaultProperties). This should not be called from my simple FieldCollection.MoveElementAtIndex test, right?
  • Let's say I finally have my product objects now, and I'm trying to add them to my collection.
  • But the ProductCollection.Add(MyProduct) checks if the underlying KeyedList already contains the product. This is also business logic that I should avoid, not being related to my test. The question is how?
  • Also, in this Add method, some events are raised, notifying the system about several things (e.g., that a new product was added to the collection). These should also not be fired at all I suppose.
  • And then finally, when I have my products added, I'm calling the desired SUT: the move elements method.
  • But this method also has logic that can be out of scope for my test: it verifies that the underlying KeyedList actually contains those fields, it calls KeyedList.Remove(), KeyedList.Insert() for its moving logic, and it fires events like CollectionModified.

如果您能向我解释如何正确进行此单元测试,如何避免调用底层对象,我将不胜感激.

If you could just explain me how to do this unit test properly, how to avoid underlying objects from being called, I would really appreciate it.

我正在考虑Microsoft的Moles框架(VS2010),因为我印象中它不需要我重构所有内容,因为这绝对不是一种选择.但是已经尝试过了,仍然找不到合适的使用方式.

I am thinking of Microsoft's Moles framework (VS2010), since I have the impression that it does not require me to refactor everything, as this is absolutely not an option. But having tried it already, still can't find a proper way to use it.

此外,我印象中,这个具体示例将对我的情况有所帮助,因为这是现实世界中通常的代码.

Also, I have the impression that this concrete example will help many in my situation, because this is how code in real world usually is.

有什么想法吗?

推荐答案

您的代码在设计时并未考虑单元测试,因此很难做到这一点.我建议您正确设计和对新代码进行单元测试,并尝试重构最重要的内容,以便可以对它进行单元测试.

Your code isn't designed with unit testing in mind which makes it very hard to do so. I'd advise you to design and unit test your new code properly and try to refactor the most important things so you can unit test that.

示例:

但是Product类的构造函数做了几件事. 它为新创建的产品计算唯一的ID:this.ID = IDUtils.ComputeNewIDBasedOnTheMoonPhase().我想我不应该测试 这都不是,因为这不是我的范围.我应该如何避免这样的电话 在这样的深度?

But the constructor of Product class does several things. It computes a unique ID for the newly created product: this.ID = IDUtils.ComputeNewIDBasedOnTheMoonPhase(). I suppose I should not test this neither, since it's not my scope. How should I avoid such calls at this level of deepness?

要解决此问题,您应该将接口IUtils传递给Product构造函数.要测试您的Product类,您可以创建一个IUtil的模拟物,该模拟物返回一个设定值.您可以对ProductProperties进行同样的操作.

To fix this you should pass an interface IUtils to your Product constructor. To test your Product class, you can create a mock of your IUtils that returns a set value. You can do the same with your ProductProperties.

此外,在此Add方法中,引发了一些事件,通知系统 关于几件事(例如,将新产品添加到了 收藏).我猜这些都不应该被解雇.

Also, in this Add method, some events are raised, notifying the system about several things (e.g., that a new product was added to the collection). These should also not be fired at all I suppose.

这归结为设计.您可以在单元测试时使用观察者模式,而没有任何观察者.

This comes down to design. You could use an observer pattern and not have any observers while unit testing.

这篇关于单元测试:如何使用大量的基础对象和业务逻辑来测试方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆