类方法的Python单元测试

类方法的Python单元测试,python,unit-testing,Python,Unit Testing,初级水平的问题。。试图了解如何最好地使用内置的unittest。在下面这个简单的例子中,方法consume\u food拾取一个食物项目,然后我调用food.cut()方法。 将来,此方法可能会返回Drink对象的实例。注释代码指出了一种可能的未来实现。在这种情况下,self.milk将不定义切割方法 我想为consumer\u food和pick\u food方法添加一个单元测试。我希望首先对原始实现执行此操作,然后在添加self.milk功能后对其进行更改 EDIT:目的是为现有api编写一

初级水平的问题。。试图了解如何最好地使用内置的
unittest
。在下面这个简单的例子中,方法consume\u food拾取一个食物项目,然后我调用
food.cut()
方法。 将来,此方法可能会返回
Drink
对象的实例。注释代码指出了一种可能的未来实现。在这种情况下,
self.milk
将不定义切割方法

我想为
consumer\u food
pick\u food
方法添加一个单元测试。我希望首先对原始实现执行此操作,然后在添加
self.milk
功能后对其进行更改

EDIT:目的是为现有api编写一个单元测试,以便捕获任何此类更改(即缺少
Drink.cut
方法),迫使我更新方法和单元测试

有人能帮我演示一下如何为这个例子编写单元测试吗

class Fruit:
    def cut(self):
        print("cut the fruit")

class Drink:
    def pour(self):
       print("pour the drink")


class A:
   def __init__(self):
       self.apple = Fruit()
       self.banana=Fruit()
       #self.milk = Drink()
       #self.liquid_diet = True

   def consume_food(self):
       food = pick_food()
       food.cut()
       print("consuming the food")

   def pick_food(self):
       return self.apple                                 
       #if self.liquid_diet: return self.milk
       #return self.apple

问题是,您的
cut()
consume\u food()
方法现在实际上做的不多,在您在测试中执行这些方法后,它们不会让您变得有意义

因此,我建议对初始代码进行一点扩展,使这些方法作用于相应的对象,以便在调用这些方法后可以对它们的状态做出有意义的断言

现在,他们真正要做的就是向STDOUT写入数据,这是一种全局状态,应该也是。(我并不是说打印输出是一件坏事——但如果这是您的代码唯一能做的事情,那么测试将非常棘手)

因此,我引入了一个常见的超类
Food
,它有一个
consume()
方法,并设置了相应的属性。类似地,
Fruit
上的
cut()
方法现在设置了一个可以测试的属性

import unittest


class Food(object):
    def __init__(self):
        self.consumed = False

    def consume(self):
        self.consumed = True


class Fruit(Food):
    def __init__(self):
        super(Fruit, self).__init__()
        self.been_cut = False

    def cut(self):
        print("cut the fruit")
        self.been_cut = True


class Consumer(object):
    def __init__(self):
        self.apple = Fruit()
        self.banana = Fruit()

    def consume_food(self):
        food = self.pick_food()
        food.cut()
        print("consuming the food")
        food.consume()

    def pick_food(self):
        return self.apple
这些测试现在可以在调用相关方法后对对象的状态进行断言。请注意,它们遵循以下规则:

  • 首先,按照需要的方式排列受测对象(实例化消费者)
  • 然后对测试对象执行操作(调用有问题的方法)
  • 最后,对预期对象所处的结果状态进行断言

我认为除了单元测试之外,您还需要考虑您的API将是什么。现在你的API是这样的:
消费食物
假设所有食物都可以被切割。如果您编写的单元测试依赖于能够调用
food.cut()
,那么如果您添加的食品没有
.cut()
,那么它将失败。这是不可避免的;您不能编写一个无论如何更改API都能始终工作的测试。所以我真的不明白你的问题是什么。@BrenBarn我想这正是OP:提供一个一旦所有食物都可以被切割的假设不再成立就会失败的测试,迫使他在实现新功能之前重构代码。@LukasGraf:好的,因此,任何调用
消费食物
的测试都可以做到这一点。@BrenBarn:这是目的之一。我想为一个现有的api编写一个测试,这样我就可以捕获任何这样的更改(即缺少
Drink.cut
method)。。。是的,我可以添加一些hasattr/断言或isinstance条件,但我想了解的是,‘我可以在这里使用unittest吗?’?如果是的话,怎么写?有人能给我举个例子吗?我知道以后需要更改。谢谢!添加print语句只是为了创建这个示例。现在我了解了如何在这种情况下编写基本测试。
class TestConsumer(unittest.TestCase):

    def test_consume_food_consumes_the_apple(self):
        c = Consumer()
        c.consume_food()
        self.assertTrue(c.apple.consumed,
                        "Expected apple to be consumed")

    def test_consume_food_cuts_the_food(self):
        c = Consumer()
        c.consume_food()
        self.assertTrue(c.apple.been_cut,
                        "Expected apple to be cut")

    def test_pick_food_always_selects_the_apple(self):
        c = Consumer()
        food = c.pick_food()
        self.assertEquals(c.apple, food,
                          "Expected apple to have been picked")


if __name__ == '__main__':
    unittest.main()