如何解决应该为吸气剂和吸气剂编写单元测试吗?
| 我们应该为吸气剂和塞脂剂编写测试,还是过分杀伤力?解决方法
我会说不。
@Will说您应该争取100%的代码覆盖率,但是我认为这是一种危险的干扰。您可以编写具有100%覆盖率的单元测试,但绝对不能进行任何测试。
单元测试可以用一种表达性的,有意义的方式来测试代码的行为,而getter / setter方法只是达到目的的一种手段。如果您使用getter / setter进行测试以实现其测试“真实”功能的目标,那么这已经足够了。
另一方面,如果您的getter和setter所做的不仅仅是获取和设置(即它们是适当的复杂方法),那么是的,应该对其进行测试。但是不要写单元测试用例只是为了测试一个或多个吸气剂,那是浪费时间。
, 罗伊·奥什罗夫(Roy Osherove)在他着名的著作《单元测试的艺术》中说:
属性(Java中的getter / setter)是很好的示例代码,通常不包含任何逻辑,也不需要测试。但是请注意:在属性中添加任何检查后,您将要确保逻辑已经过测试。
,TDD的确是肯定的
注意:尽管可能是一个坏建议,但此答案仍会不断增加。要了解原因,请在下面看看它的妹妹。
颇有争议,但我认为,对这个问题回答“否”的任何人都缺少TDD的基本概念。
对我来说,如果您遵循TDD,答案是肯定的。如果不是,那么不合理的答案。
TDD中的DDD
TDD通常被认为具有主要优点。
防御
确保代码可能会更改,但行为不会更改。
这允许进行非常重要的重构实践。
您是否获得此TDD。
设计
在实施之前,您可以指定应做的事情,行为方式。
这通常意味着更明智的实施决策。
文献资料
测试套件应作为规范(要求)文档。
为此目的使用测试意味着文档和实现始终处于一致状态-对一个进行更改意味着对另一个进行更改。与保留要求和在单独的Word文档上进行设计相比。
将责任与实施分开
作为程序员,将属性视为重要的事物而将获取器和设置器视为某种开销是非常诱人的。
但是属性是实现细节,而setter和getter是使程序真正起作用的契约接口。
拼写一个对象应该:
允许其客户更改其状态
和
允许其客户查询其状态
然后实际存储此状态的方式(最常见的属性是唯一的属性)。
诸如
(The Painter class) should store the provided colour
对于TDD的文档部分很重要。
当您编写测试时,最终的实现是微不足道的(属性)并且没有任何防御优势的事实对您来说应该是未知的。
缺乏往返工程...
系统开发领域中的关键问题之一是缺乏往返工程1-系统的开发过程被分为多个相互分离的子过程,这些子过程的工件(文档,代码)通常不一致。
1布罗迪(Brodie),迈克尔·L(Michael L.),“约翰·米洛普洛斯(John Mylopoulos):缝制概念模型的种子。”概念模型:基础和应用。 Springer Berlin Heidelberg,2009年。1-9。
...以及TDD如何解决
TDD的文档部分可确保系统规范及其代码始终保持一致。
先设计,后实施
在TDD中,我们首先编写不合格的测试,然后再编写使他们通过的代码。
在更高级别的BDD中,我们首先编写方案,然后使它们通过。
为什么要排除二传手和吸气剂?
从理论上讲,在TDD中,完全有可能由一个人编写测试,而由另一个人来实现通过测试的代码。
因此,问问自己:
编写课程测试的人是否应该提及吸气剂和吸气剂。
由于getter和setter是类的公共接口,因此答案显然是肯定的,否则将无法设置或查询对象的状态。但是,执行此操作的方法不一定是分别测试每种方法,有关更多信息,请参见我的其他答案。
显然,如果您首先编写代码,答案可能不会那么清晰。
,tl; dr:是的,您应该这样做,而使用OpenPojo则很简单。
您应该在获取器和设置器中进行一些验证,以便进行测试。例如,setMom(Person p)
不允许将年龄小于自己的任何人设置为母亲。
即使您现在不做任何事情,将来也很有可能,那么这对于回归分析将是一个很好的选择。如果您希望允许将母亲设置为“ 2”岁,则应该对此进行测试,以便以后有人进行更改时,这会加强您的假设。
常见的错误是“ 3”,应为“ 4”。 (在第一种情况下,要写入的“ 5”不是对象上的“ 5”字段的参数)。
如果要返回数组或集合,则应在返回之前测试getter是否将对传递给setter的数据进行防御性复制。
否则,如果您拥有最基本的设置器/获取器,则对每个对象进行单元测试最多可能会增加大约10分钟,那么损失是什么?如果添加行为,则您已经有骨架测试,并且可以免费获得此回归测试。如果您使用的是Java,则没有任何借口,因为这里有OpenPojo。您可以启用一组现有规则,然后使用它们扫描整个项目,以确保在代码中一致地应用它们。
从他们的例子:
final PojoValidator pojoValidator = new PojoValidator();
//create rules
pojoValidator.addRule( new NoPublicFieldsRule () );
pojoValidator.addRule( new NoPrimitivesRule () );
pojoValidator.addRule( new GetterMustExistRule () );
pojoValidator.addRule( new SetterMustExistRule () );
//create testers
pojoValidator.addTester( new DefaultValuesNullTester () );
pojoValidator.addTester( new SetterTester () );
pojoValidator.addTester( new GetterTester () );
//test all the classes
for( PojoClass pojoClass : PojoClassFactory.getPojoClasses( \"net.initech.app\",new FilterPackageInfo() ) )
pojoValidator.runValidation( pojoClass );
, 是的,但并非总是孤立
请允许我详细说明:
什么是单元测试?
从有效使用旧版代码1:
术语“单元测试”在软件开发中具有悠久的历史。普遍于
单元测试的大多数概念是它们是独立于个人的测试
软件组件。什么是成分?定义各不相同,
但是在单元测试中,我们通常关心系统中最原子的行为单元。在过程代码中,单位通常是功能。在面向对象的代码中,单位是类。
请注意,在OOP中,您可以找到getter和setter,单位是类,而不一定是单个方法。
什么是好的测试?
所有要求和测试都遵循Hoare逻辑的形式:
{P} C {Q}
哪里:
{P}
是前提(给定)
C
为触发条件(当)
{Q}
是后置条件(然后)
然后是格言:
测试行为,而不是实现
这意味着您不应测试C
如何达到后置条件,而应检查{Q}
是C
的结果。
说到OOP ,,9ѭ是一门课。因此,您不应该测试内部效果,而只能测试外部效果。
为什么不单独测试bean的获取器和设置器
获取器和设置器可能涉及一些逻辑,但是很久以来,该逻辑没有外部影响-使它们成为bean访问器。2)测试将不得不查看对象内部,不仅破坏了封装,还测试了实现。
因此,您不应该单独测试bean的getter和setter。这是不好的:
Describe \'LineItem class\'
Describe \'setVAT()\'
it \'should store the VAT rate\'
lineItem = new LineItem()
lineItem.setVAT( 0.5 )
expect( lineItem.vat ).toBe( 0.5 )
尽管如果setVAT
会引发异常,则相应的测试将是适当的,因为现在存在外部影响。
您应该如何测试吸气剂和吸气剂?
如果对象内部的状态对外部没有影响,则实际上没有任何改变的余地,即使这种影响稍后出现。
因此,对setter和getter的测试应关注这些方法的外部效果,而不是内部方法。
例如:
Describe \'LineItem class\'
Describe \'getGross()\'
it \'should return the net time the VAT\'
lineItem = new LineItem()
lineItem.setNet( 100 )
lineItem.setVAT( 0.5 )
expect( lineItem.getGross() ).toBe( 150 )
您可能会想:
请稍等,我们正在测试getGross()
,而不是setVAT()
。
但是,如果“ 19”故障,则该测试也将全部失败。
1Feathers,M.,2004年。有效处理遗留代码。 Prentice Hall专业人士。
2Martin,R.C.,2009年。简洁代码:敏捷软件工艺手册。培生教育。
,尽管有合理的理由可以使用属性,但是有一种常见的面向对象设计信念,即通过属性公开成员状态是不好的设计。罗伯特·马丁(Robert Martin)关于开放封闭原理的文章对此进行了扩展,指出“属性”鼓励耦合,因此限制了关闭类以使其无法修改的能力-如果您修改了该属性,则该类的所有使用者也将需要更改。他认为公开成员变量不一定是不良的设计,可能只是不良的风格。但是,如果属性是只读的,则滥用和副作用的机会就更少。
我可以为单元测试提供的最佳方法(这似乎很奇怪)是使尽可能多的属性成为受保护的或内部的。这将防止耦合,同时阻止编写针对吸气剂和吸气剂的愚蠢测试。
有明显的原因应该使用读/写属性,例如绑定到输入字段的ViewModel属性等。
实际上,单元测试应该通过公共方法来驱动功能。如果您要测试的代码恰好使用了这些属性,那么您将免费获得代码覆盖率。如果事实证明这些属性从未被代码覆盖范围突出显示,则很有可能:
您缺少间接使用属性的测试
属性未使用
如果编写用于getter和setter的测试,则会产生错误的覆盖率感,并且无法确定功能行为是否实际使用了这些属性。
, 如果getter和/或setter的循环复杂度为1(通常为1),则答案为否,您不应该这样做。
因此,除非您拥有要求100%代码覆盖率的SLA,否则请不要打扰,并专注于测试软件的重要方面。
附言记住要区分getter和setter,即使在C#之类的语言中,属性似乎是同一回事。设置器的复杂度可能会比吸气器高,因此可以验证单元测试。
, 一个幽默而又明智的观点:证言之道
\“写下您今天可以做的测试\”
如果您是一位经验丰富的测试人员,并且这是一个小项目,那么测试吸气剂/吸气剂可能会显得过高。但是,如果您刚刚开始学习如何进行单元测试,或者这些获取器/设置器可能包含逻辑(例如@ArtB \'ssetMom()
示例),那么编写测试将是一个好主意。
, 实际上,这实际上是我和我团队之间的话题。我们拍摄了80%的代码。我的团队认为,getter和setter是自动实现的,并且编译器正在幕后生成一些基本代码。在这种情况下,由于生成的代码是非侵入性的,因此测试编译器为您创建的代码实际上没有任何意义。我们还讨论了异步方法,在这种情况下,编译器会在后台生成一堆代码。这是另一种情况,我们要进行测试。长话短说,将其与您的团队联系起来,并自己决定是否值得测试。
另外,如果您像我们一样使用代码覆盖率报告,您可以做的一件事就是添加[ExcludeFromCodeCoverage]属性。我们的解决方案是将其用于仅具有使用getter和setter或属性本身的属性的模型。这样一来,假设您正在使用它来计算代码覆盖率百分比,那么在运行代码覆盖率报告时,它不会影响总代码覆盖率%。测试愉快!
,我认为代码覆盖率是查看是否错过了应覆盖的任何功能的好方法。
当您通过漂亮的颜色手动检查coverage时,可以说不需要对普通的getter和setter进行测试(尽管我总是这样做)。
当您仅检查项目上的代码覆盖率百分比时,像80%这样的测试覆盖率百分比就没有意义。您可以测试所有非逻辑部分,而忽略一些关键部分。在这种情况下,只有100%意味着您已经测试了所有重要代码(以及所有非逻辑代码)。一旦达到99.9%,您就会知道已经忘记了一些东西。
顺便说一句:代码覆盖率是检查您是否已经完全(单元)测试一个类的最终检查。但是100%的代码覆盖率并不一定意味着您已经实际测试了该类的所有功能。因此,单元测试应始终按照类的逻辑进行。最后,您运行覆盖范围以查看是否忘记了任何内容。当做得对时,您第一次击中100%。
还有一件事:最近在荷兰的一家大型银行工作时,我注意到Sonar表示100%的代码覆盖率。但是,我知道有些东西丢失了。如果检查每个文件的代码覆盖率百分比,则表明文件的百分比较低。整个代码库的百分比很大,以至于一个文件没有使该百分比显示为99.9%。所以您可能要注意这一点...
, 我对JUnit代码本身实现的覆盖率进行了一些分析。
一类未发现的代码是“测试太简单”。这包括简单的getter和setter,JUnit的开发人员不进行测试。
另一方面,JUnit的方法(不建议弃用的方法)长于3行,而该方法未包含在任何测试中。
, 我会说:是的
getter / setter方法中的错误可能会悄悄地潜入并引起一些难看的错误。
我编写了一个lib程序,使此程序和其他一些测试更容易。
您必须在JUnit测试中编写的唯一内容是:
assertTrue(executor.execute(Example.class,Arrays.asList( new DefensiveCopyingCheck(),new EmptyCollectionCheck(),new GetterIsSetterCheck(),new HashcodeAndEqualsCheck(),new PublicVariableCheck())));
-> https://github.com/Mixermachine/base-test
, 是的,特别是如果要获取的项是抽象类的子类的对象。您的IDE可能会也可能不会提醒您某些属性尚未初始化。
然后一些显然无关的测试崩溃,结果为NullPointerException
,这需要花费一些时间才能弄清楚,实际上并没有可获取的属性。
尽管那仍然不会像在生产中发现问题那样糟糕。
确保所有抽象类都具有构造函数可能是一个好主意。如果不是,则对吸气剂的测试可能会提醒您那里存在问题。
至于基元的获取器和设置器,问题可能是:我正在测试程序还是在测试JVM或CLR?一般来说,不需要测试JVM。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。