Begginer level question, I am quite new and wanted to learn using unit test in my code. I've watched some tutorials how to make unittests, but when comes to practice it on your own code I start wonder how to make it properly to avoid learn bad code habits.
I have a class Geometry that will be inherited by other class, that class use imported custom object (namedtuple "Point") and list from json file with configuration but this will be provided by other part of code. Here are my questions:
- Does my unittests should only check class methods create_geometry and calculate_drag_surfaces or also all mentioned above and instance creation with init method ?
- When I create unitest of method that affect instance property, like create_geometry method do, how asserts should look like ? I should check value of changed instance property or there is a way to test it "in-place" without new instance creation ?
- How should I make unittest for protected or hidden methods, I mean is there any difference there ?
If you will find any issues in my code I'm open to hear any suggestions I don't have any commercial experience and want to learn as much as I can. Below I presented code I want to test with unittest.
from point import Point
class Geometry:
"""
Geometry class - object that will keep geometry dependent information necessary for
graphic render and physic calculations
"""
def __init__(self, geometry_points_cords, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry_points = [] # list of named tuples with co-ords on flat surface
self.__create_geometry(geometry_points_cords)
self.x_drag_surface = None
self.y_drag_surface = None
self.__calculate_drag_surfaces()
def __create_geometry(self, geometry_points_cords):
"""
Method that will convert provided geometry points into namedtuples that describe
geometry on x/y plane
:param geometry_points_cords:
:return:
"""
for geometry_cords in geometry_points_cords:
self.geometry_points.append(Point(geometry_cords[0], geometry_cords[1]))
def __calculate_drag_surfaces(self):
"""
Method that will calculate drag surfaces in each axis base on geometry
:return:
"""
x_cords = []
y_cords = []
for single_point in self.geometry_points:
x_cords.append(single_point.x)
y_cords.append(single_point.y)
self.x_drag_surface = (max(x_cords) - min(x_cords))**2
self.y_drag_surface = (max(y_cords) - min(y_cords))**2
CodePudding user response:
Is the interface the two fields x_drag_surface
and y_drag_surface
? Then you should primarily test that those get the proper values.
geometry = Geometry(some_coordinates)
assert geometry.x_drag_surface = correct_x_drag_surface
assert geometry.y_drag_surface = correct_y_drag_surface
As the code is written now you can not test __create_geometry
and __calculate_drag_surfaces
separately since they will both be run by the constructor. You can extract them from the class, though, and make them testable:
def make_points(coordinates):
"""
Method that will convert provided geometry points into namedtuples that describr geometry on x/y plane
:param geometry_points_cords:
:return:
"""
return [ Point(x, y) for (x, y) in coordinates]
def calculate_drag_surfaces(points):
"""
Method that will calculate drag surfaces in each axis base on geometry
:return:
"""
x_coords = list(map(lambda p: p.x, points))
y_coords = list(map(lambda p: p.y, points))
x_drag_surface = (max(x_coords) - min(x_coords))**2
y_drag_surface = (max(y_coords) - min(y_coords))**2
return x_drag_surface, y_drag_surface
class Geometry:
"""
Geometry class - object that will keep geometry dependent information necessary for
graphic render and physic calculations
"""
def __init__(self, coordinates, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry_points = make_points(coordinates) # list of named tuples with co-ords on flat surface
self.x_drag_surface, self.y_drag_surface = calculate_drag_surfaces(self.geometry_points)