为python代码自动生成单元测试
auger-python的Python项目详细描述
螺旋钻
auger是一个为python代码自动生成单元测试的项目。
见 these slides 或 this blog 更多信息请登录。
安装
使用以下部件安装螺旋输送器:
pip install auger-python
运转螺旋输送器
要为python 2或3的任何类或模块生成单元测试,请执行以下操作:
import auger
with auger.magic([ <any list of modules or classes> ]):
<any code that exercises your application>
一个简单的例子
下面是一个完全不依赖螺旋钻的简单示例:
class Foo: # Declare a class with a method
def bar(self, x):
return 2 * x . # Duplicate x and return it
def main():
foo = Foo() # Create an instance of Foo
print(foo.bar(32)) # Call the bar method and print the result
main()
在main
函数中,我们调用bar
方法,它将打印64。
在我们的简单示例中运行螺旋钻
为了生成这个类的单元测试,我们再次运行代码,但这次是在auger的上下文中:
import auger
with auger.magic([Foo]):
main()
这将打印以下内容:
64
Auger: generated test: tests/test_Foo.py
生成的测试如下所示,删除了一些main的导入和测试:
import unittest
class FooTest(unittest.TestCase):
def test_bar(self):
foo_instance = Foo()
self.assertEquals(
foo_instance.bar(x=32),
64
)
if __name__ == "__main__":
unittest.main()
在详细模式下运行螺旋输送器
除了在文件系统中发出测试,auger还可以将测试打印到控制台,
通过使用verbose
参数:
import auger
with auger.magic([Foo], verbose=True):
main()
在这种情况下,螺旋钻不会生成任何测试,而只是打印出来。
更大的示例
考虑下面的例子,pet.py
,包含在sample
文件夹中,它允许我们创建一个Pet
,其中包含一个名称和一个种类:
from animal import Animal
class Pet(Animal):
def __init__(self, name, species):
Animal.__init__(self, species)
self.name = name
def getName(self):
return self.name
def __str__(self):
return "%s is a %s" % (self.getName(), self.getSpecies())
def createPet(name, species):
return Pet(name, species)
一个Pet
实际上是一种特殊的Animal
,它有一个名字,定义在animal.py
:
class Animal(object):
def __init__(self, species):
self.species = species
def getSpecies(self):
return self.species
有了这两个定义,我们可以创建一个Pet
实例并打印出一些详细信息:
import animal
import pet
def main():
p = pet.createPet("Polly", "Parrot")
print(p, p.getName(), p.getSpecies())
main()
这将产生:
Polly is a Parrot Polly Parrot
在更大的示例中调用螺旋输送器
使用auger,我们可以记录对pet.py
中定义的所有函数和方法的所有调用,
同时还要记住从pet.py
到其他模块的所有调用的详细信息,
所以他们可以被嘲笑。
而不是说:
if __name__ == "__main__":
main()
我们会说:
import auger
if __name__ == "__main__":
with auger.magic([pet]): # this is the new line and invokes Auger
main()
这将为pet.py
生成以下自动生成的单元测试:
from mock import patch
from sample.animal import Animal
import sample.pet
from sample.pet import Pet
import unittest
class PetTest(unittest.TestCase):
@patch.object(Animal, 'get_species')
@patch.object(Animal, 'get_age')
def test___str__(self, mock_get_age, mock_get_species):
mock_get_age.return_value = 12
mock_get_species.return_value = 'Dog'
pet_instance = Pet('Clifford', 'Dog', 12)
self.assertEquals(pet_instance.__str__(), 'Clifford is a dog aged 12')
def test_create_pet(self):
self.assertIsInstance(sample.pet.create_pet(age=12,species='Dog',name='Clifford'), Pet)
def test_get_name(self):
pet_instance = Pet('Clifford', 'Dog', 12)
self.assertEquals(pet_instance.get_name(), 'Clifford')
def test_lower(self):
self.assertEquals(Pet.lower(s='Dog'), 'dog')
if __name__ == "__main__":
unittest.main()
注意,auger检测对象创建、方法调用和静态方法。它是自动的
为Animal
生成模拟。模拟get_species
返回“dog”,而get_age
返回12。
也就是说,这些是我们上次运行示例代码时auger记录的值。
螺旋钻的优点
通过自动生成单元测试,我们大大降低了软件成本 发展。测试本身旨在帮助开发人员进行单元测试 并降低如何编写测试的学习曲线。
螺旋钻的已知限制
auger不尝试用合成值(如-1
、None
或[]
)替换参数。
当代码使用异常时,auger也不能很好地工作。auger也不喜欢有decorator的方法。
auger只记录给定的执行运行并将运行保存为测试。俄歇不知道代码是否真的 按预期工作。如果代码包含一个bug,auger将简单地记录bug行为。没有免费的 在这里吃午饭。由开发人员来验证代码是否有效。