我有一个 Python 单元测试,其中一些测试具有相同类型的对象。一个测试类的基本大纲是:
class TestClass(unittest.TestCase):
def setup(self):
...
def checkObjects(self, obj):
for i in [...values...]:
self.assertEqual(starttags(i,obj), endtags(i,obj))
def testOne(self):
#Get object one.
checkObjects(objone)
def testAnother(self):
#Access another object.
checkObjects(another)
... various tests for similar objects.
虽然它是模块化的,但我注意到任何失败都会给出类似 AssertionError: number != anothernumber 的错误,以及生成错误的代码行 self.assertEqual(starttags(i,obj), endtags(i ,obj))。如果我列出了测试而不是放在 for 循环中,我会得到类似的东西:
self.assertEqual(starttags(value1,obj), endtags(value1,obj))
self.assertEqual(starttags(value2,obj), endtags(value2,obj))
它准确地显示了导致错误的情况,但是是复制粘贴代码,我认为通常不推荐这样做。我最近注意到这个问题,当时一位贡献者重新设计了一个更干净 的单元测试,不幸的是,它几乎不会提供关于断言失败的调试信息。那么,在这些情况下,最佳做法是什么?像元组列表这样的东西,用 assertEquals 送入 for 循环是“更干净的”,但是在不同行上复制粘贴不同的值会提供有用的堆栈跟踪。
最佳答案
如果更干净是指更少的代码,那么这种更干净的代码并不总是更可读的代码。事实上,它通常可读性较差(尤其是当您回头看时)。你总是可以进行花哨的重构,但你需要知道何时停止。从长远来看,使用更明显、更简单的代码总是比试图压缩少一行代码以获得人为 yield 更好——不仅仅是在单元测试方面。
单元测试有自己的规则。例如,它们通常允许与您的常规代码标准所说的不同的命名约定,您几乎从不记录它——它们是您代码库的特殊部分。此外,重复代码并不少见。实际上,进行许多外观相似的小型测试是很典型的。
目前,即使在编写测试的阶段,您的测试也令人困惑 - 想象一下从现在起 3 个月后回到该代码。想象一下,由于其他人在其他地方 进行了一些更改,其中一个测试失败了。它不会变得更好。
以这样一种方式设计您的测试,当其中一个失败时,您立即知道它为什么会这样以及在哪里。不仅如此 - 以这样一种方式设计它们,您可以在眨眼间分辨出它们在做什么。在测试代码中使用 for 循环、ifs 和基本上任何其他类型的控制流 机制(或过于广泛的重构)通常会导致一个问题突然想到 - 我们在这里做什么? 这是您不希望自己问的那种问题。
用比我聪明的人的话来总结这篇长篇文章:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999
帮自己一个忙,坚持这条规则。
关于Python 单元测试模块化与可读性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9271925/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test