注意:我习惯在C#代码中使用依赖注入, 但据我所知,Ruby和Python等动态语言都是 像play-doh not LEGOs一样,因此不需要使用IoC 容器,虽然有关IoC模式是否仍然有用的争论。在下面的代码中,我使用了fudge的
.patch
功能,该功能提供了模拟/存根代码所需的接缝。但是,代码的组件因此耦合。我不确定我喜欢这个。 This SO answer也解释了动态语言中的耦合比静态语言更宽松,但是在该问题中引用了另一个答案,即IoC的工具不需要,但模式不是。所以一个侧面的问题是,“我应该使用DI吗?”
我正在使用以下python框架:
以下是生成的生产代码:
def to_fasta(seq_records, file_name):
file_object = open(file_name, "w")
Bio.SeqIO.write(seq_records, file_object, "fasta")
file_object.close()
现在我做了TDD这段代码,但是我做了以下测试(这不是全部彻底):
@istest
@fudge.patch('__builtin__.open', 'Bio.SeqIO.write')
def to_fasta_writes_file(fake_open, fake_SeqIO):
fake_open.is_a_stub()
fake_SeqIO.expects_call()
seq_records = build_expected_output_sequneces()
file_path = "doesn't matter"
to_fasta(seq_records, file_path)
以下是更新后的测试以及明确的注释,以确保我遵循Four-Phase Test模式:
@istest
@fudge.patch('__builtin__.open', 'Bio.SeqIO')
def to_fasta_writes_file(fake_open, fake_SeqIO):
# Setup
seq_records = build_expected_output_sequneces()
file_path = "doesn't matter"
file_type = 'fasta'
file_object = fudge.Fake('file').expects('close')
(fake_open
.expects_call()
.with_args(file_path, 'w')
.returns(file_object))
(fake_SeqIO
.is_callable()
.expects("write")
.with_args(seq_records, file_object, file_type))
# Exercise
to_fasta(seq_records, file_path)
# Verify (not needed due to '.patch')
# Teardown
虽然第二个例子更彻底,但这个测试是否过度杀伤? TDD python代码有更好的方法吗?基本上,我正在寻找有关我如何使用TDDing此操作的反馈,并欢迎任何其他方法来编写测试代码或生产代码。
答案 0 :(得分:1)
想想这个功能的作用,并思考你实际负责的内容。它看起来像:给定一些数据和文件名,以特定格式(fasta)将记录写入文件。您实际上并不负责Python文件I / O的工作方式,也不负责Bio.SeqIO的工作原理。
您的第二个版本测试:
看起来很不错。大部分都很简单,有些人可能会称之为矫枉过正,但TDD方法可以帮助提醒你做一些像关闭文件的事情(很明显,但我们都会忘记这样的事情)。这些测试还可以防止Bio.SeqIO.write在将来被更改以期望不同的参数。您可以升级您的库版本并想知道您的程序中断的原因,或者升级您的库版本,运行测试以及知道它中断的原因和位置。
当你无法打开文件或Bio.SeqIO.write可能抛出的任何异常时,你应该为这种情况编写其他测试。