
Unit Tests & Classes¶
Tomas Beuzen, September 2020
These exercises complement Chapter 3.
import math
Exercises¶
1.¶
The function area() accepts the argument radius and calculates the area of a circle. Write three tests using assert statements for the following conditions:
Assert that
area(1)returns afloat;Assert that
area(0)returns a value of 0;Assert that
area(5)is approximately equal to 78.5 (hint:math.isclose(..., abs_tol=0.1))
def area(radius):
"""Calculate the area of a circle based on the given radius."""
return math.pi * radius ** 2
# Your answer here.
2.¶
In the spirit of the EAFP (easier to ask for forgiveness than permission) philosophy. Modify the code of the function area() and add a try/except statement to catch the type error raised by passing a string to area() as shown below:
area('10')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-28e1bc493b84> in <module>
----> 1 area('10')
<ipython-input-2-13e66cca8177> in area(radius)
1 def area(radius):
2 """Calculate the area of a circle based on the given radius."""
----> 3 return math.pi * radius ** 2
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
def area(radius):
"""Calculate the area of a circle based on the given radius."""
pass # Remove this line and add your answer here.
3.¶
In the spirit of the LBYL (look before you leap) philosophy. Modify the code of the function area() and add a conditional if/else statement to make sure that a user has passed a number (int or float) to the area() function. If they pass something else, raise a TypeError.
def area(radius):
"""Calculate the area of a circle based on the given radius."""
pass # Remove this line and add your answer here.
4.¶
For this exercise I want you to create a class called Circle. It should have the following characteristics:
It should be initiated with the argument
radiusand store this as an instance attribute.Have a method
area()which calculates the area of the circle.Have a method
circumference()which calculates the circumference of the circle.Have the method
__str__()which is a special method in Python and controls what is output to the screen when youprint()an instance of your class (learn more here). Theprint()statement should print the stringf"A Circle with radius {self.radius}".
I’ve provided some tests for you to check your class.
class Circle:
"""A circle with a radius r."""
pass # Remove this line and add your answer here.
assert Circle(3).radius == 3, "Test 1 failed."
assert math.isclose(Circle(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
assert math.isclose(Circle(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
assert Circle(3).__str__() == "A Circle with radius 3", "Test 4 failed."
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-5dbdbcaa4346> in <module>
----> 1 assert Circle(3).radius == 3, "Test 1 failed."
2 assert math.isclose(Circle(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
3 assert math.isclose(Circle(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
4 assert Circle(3).__str__() == "A Circle with radius 3", "Test 4 failed."
TypeError: Circle() takes no arguments
5.¶
Now, let’s create a new class sphere that inherits from the circle class we created above. It should have the following characteristics:
It should be initiated exactly the same as
Circlewas, with the single argumentradiuswhich is stored as an instance attribute.Have a method
volume()which calculates the volume of the sphere (\(\frac{4}{3}{\pi}{r^3}\)).Outputs the string
f"A Sphere with volume 4.19"when you callprint(Sphere(1))(hint: recall the__str__()method from the previous question).
I’ve provided some tests for you to check your class.
# Your answer here.
assert Sphere(3).radius == 3, "Test 1 failed."
assert math.isclose(Sphere(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
assert math.isclose(Sphere(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
assert math.isclose(Sphere(3).volume(), 113.1, abs_tol=0.1), "Test 3 failed."
assert Sphere(1).__str__() == "A Sphere with volume 4.19", "Test 4 failed."
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-10-605d8a1c6bb6> in <module>
----> 1 assert Sphere(3).radius == 3, "Test 1 failed."
2 assert math.isclose(Sphere(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
3 assert math.isclose(Sphere(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
4 assert math.isclose(Sphere(3).volume(), 113.1, abs_tol=0.1), "Test 3 failed."
5 assert Sphere(1).__str__() == "A Sphere with volume 4.19", "Test 4 failed."
NameError: name 'Sphere' is not defined
6.¶
Imagine that users of our Sphere class often want to instantiate our class with a circumference instead of a radius. Add a class method called from_circ() to the Sphere class that allows users to do this. The method should calculate the radius from the passed circumference, and then use that radius to make an instance of Sphere.
I’ve provided some tests for you to check your modified class.
# Your answer here.
assert Sphere.from_circ(0).radius == 0, "Test 1 failed."
assert Sphere.from_circ(3 * math.pi).radius == 1.5, "Test 2 failed."
assert math.isclose(Sphere.from_circ(6).radius, 0.95, abs_tol=0.1), "Test 3 failed."
assert math.isclose(Sphere.from_circ(6).volume(), 3.65, abs_tol=0.1), "Test 4 failed."
assert Sphere.from_circ(6).__str__() == "A Sphere with volume 3.65", "Test 5 failed."
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-c64f2af0ae75> in <module>
----> 1 assert Sphere.from_circ(0).radius == 0, "Test 1 failed."
2 assert Sphere.from_circ(3 * math.pi).radius == 1.5, "Test 2 failed."
3 assert math.isclose(Sphere.from_circ(6).radius, 0.95, abs_tol=0.1), "Test 3 failed."
4 assert math.isclose(Sphere.from_circ(6).volume(), 3.65, abs_tol=0.1), "Test 4 failed."
5 assert Sphere.from_circ(6).__str__() == "A Sphere with volume 3.65", "Test 5 failed."
NameError: name 'Sphere' is not defined
Solutions¶
1.¶
The function area() accepts the argument radius and calculates the area of a circle. Write three tests using assert statements for the following conditions:
Assert that
area(1)returns afloat;Assert that
area(0)returns a value of 0;Assert that
area(5)is approximately equal to 78.5 (hint:math.isclose(..., abs_tol=0.1))
def area(radius):
"""Calculate the area of a circle based on the given radius."""
return math.pi * radius ** 2
assert isinstance(area(1), float), 'Test 1 failed!'
assert area(0) == 0, 'Test 2 failed!'
assert math.isclose(area(5), 78.5, abs_tol=0.1)
2.¶
In the spirit of the EAFP (easier to ask for forgiveness than permission) philosophy. Modify the code of the function area() and add a try/except statement to catch the type error raised by passing a string to area() as shown below:
area('10')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-28e1bc493b84> in <module>
----> 1 area('10')
<ipython-input-13-13e66cca8177> in area(radius)
1 def area(radius):
2 """Calculate the area of a circle based on the given radius."""
----> 3 return math.pi * radius ** 2
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
def area(radius):
"""Calculate the area of a circle based on the given radius."""
try:
return math.pi * radius ** 2
except TypeError:
print(f"radius should be a number but you entered a {type(radius)}")
except:
print("Some other error occurred!")
3.¶
In the spirit of the LBYL (look before you leap) philosophy. Modify the code of the function area() and add a conditional if/else statement to make sure that a user has passed a number (int or float) to the area() function. If they pass something else, raise a TypeError.
def area(radius):
"""Calculate the area of a circle based on the given radius."""
if isinstance(radius, (int, float)):
return math.pi * radius ** 2
else:
raise TypeError(f"radius should be a number but you entered a {type(radius)}")
4.¶
For this exercise I want you to create a class called circle. It should have the following characteristics:
It should be initiated with the argument
radiusand store this as an instance attribute.Have a method
area()which calculates the area of the circle.Have a method
circumference()which calculates the circumference of the circle.Have the method
__str__()which is a special method in Python and controls what is output to the screen when youprint()an instance of your class (learn more here). Theprint()statement should print the stringf"A Circle with radius {self.radius}".
I’ve provided some tests for you to check your class.
class Circle:
"""A circle with a radius r."""
def __init__(self, radius):
self.radius = radius
def area(self):
"""Calculate the area of the circle."""
return math.pi * self.radius ** 2
def circumference(self):
"""Calculate the circumference of the circle."""
return 2.0 * math.pi * self.radius
def __str__(self):
return f"A Circle with radius {self.radius}"
assert Circle(3).radius == 3, "Test 1 failed."
assert math.isclose(Circle(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
assert math.isclose(Circle(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
assert Circle(3).__str__() == "A Circle with radius 3", "Test 4 failed."
5.¶
Now, let’s create a new class sphere that inherits from the circle class we created above. It should have the following characteristics:
It should be initiated exactly the same as
Circlewas, with the single argumentradiuswhich is stored as an instance attribute.Have a method
volume()which calculates the volume of the sphere (\(\frac{4}{3}{\pi}{r^3}\)).Outputs the string
f"A Sphere with volume 4.19"when you callprint(Sphere(1))(hint: recall the__str__()method from the previous question).
I’ve provided some tests for you to check your class.
class Sphere(Circle):
"""A sphere with a radius r."""
def volume(self):
"""Calculate the volume of the sphere."""
return 4 / 3 * math.pi * self.radius ** 3
def __str__(self):
return f"A Sphere with volume {self.volume():.2f}"
assert Sphere(3).radius == 3, "Test 1 failed."
assert math.isclose(Sphere(3).area(), 28.3, abs_tol=0.1), "Test 2 failed."
assert math.isclose(Sphere(3).circumference(), 18.8, abs_tol=0.1), "Test 3 failed."
assert math.isclose(Sphere(3).volume(), 113.1, abs_tol=0.1), "Test 3 failed."
assert Sphere(1).__str__() == "A Sphere with volume 4.19", "Test 4 failed."
6.¶
Imagine that users of our Sphere class often want to instantiate our class with a circumference instead of a radius. Add a class method called from_circ() to the Sphere class that allows users to do this. The method should calculate the radius from the passed circumference, and then use that radius to make an instance of Sphere.
I’ve provided some tests for you to check your modified class.
class Sphere(Circle):
"""A sphere with a radius r."""
def volume(self):
"""Calculate the volume of the sphere."""
return 4 / 3 * math.pi * self.radius ** 3
@classmethod
def from_circ(cls, circumference):
"""Make an instance of Sphere from a circumference."""
radius = circumference / (2 * math.pi)
return cls(radius)
def __str__(self):
return f"A Sphere with volume {self.volume():.2f}"
assert Sphere.from_circ(0).radius == 0, "Test 1 failed."
assert Sphere.from_circ(3 * math.pi).radius == 1.5, "Test 2 failed."
assert math.isclose(Sphere.from_circ(6).radius, 0.95, abs_tol=0.1), "Test 3 failed."
assert math.isclose(Sphere.from_circ(6).volume(), 3.65, abs_tol=0.1), "Test 4 failed."
assert Sphere.from_circ(6).__str__() == "A Sphere with volume 3.65", "Test 5 failed."