A beginner level question.. trying to understand how I can best use the built-in unittest
. In the trivial example below, the method consume_food picks a food item and then I am calling food.cut()
method.
In future, this method may return instance of Drink
object. The #commented code
indicates one possible future implementation. In this case, self.milk
will not have the cut method defined.
I want to add a unit test for consume_food
and pick_food
methods. I would like to do this for the original implementation first and then change it after adding self.milk
functionality.
EDIT: The intention is to write a unit test for an existing api, so that I can capture any such changes ( i.e. absence of Drink.cut
method) forcing me to update the methods and unit tests.
Can someone please help showing me how to write a unit test for this example?
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
First you need to create a test file. Then import the unittest module, define the testing class that inherits from unittest. TestCase, and lastly, write a series of methods to test all the cases of your function's behavior. First, you need to import a unittest and the function you want to test, formatted_name() .
A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.
It is possible to write a main() method in each class that need to be tested for unit testing. In the main() method, you could create test object of the class itself, and write some tests to test its methods.
The thing is, your cut()
and consume_food()
methods don't really do much right now that allow you to make meaningful assertions after you execute them in a test.
So I'd suggest to expand your initial code a little bit to have those methods act upon the respective objects so that you can make meaningful assertions on their state after invoking those methods.
Right now, all they really do is write to STDOUT, which is sort of a global state - which should generally be avoided and is always difficult to test. (I'm not saying that printing output is a bad thing - but if that's the only thing your code does, it's going to be very tricky to test).
So I introduced a common superclass Food
which has a consume()
method, and sets a corresponding attribute. Similarly, the cut()
method on Fruit
now sets an attribute that you can test for.
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
These tests now can make assertions on the object's states after the relevant methods have been invoked. Note that they follow the AAA pattern - Arrange Act Assert:
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With