Допустим у нас есть задача принимать по сети xml-документ, содержащий структуру образовательного учреждения (из какого-нибудь сапа нам это выгружают), назовем его условно Школой, и вам нужно на основании этих данных вести учет средней успеваемости учеников по региону или еще какие-то данные собирать.
Что мы можем сделать? Мы делаем класс, который в ините принимает урл удаленного сервиса и реализует метод get_avg_rate. Вроде бы и все. Но давайте сделаем умнее.
Во-первых, у нас есть модели предметной области, которые описывают нашу Школу, классы в ней и учеников. Как-то так
class Student:
def __init__(self):
self.family = None
self.name = None
self.rate = None
class Group:
def __init__(self):
self.name = None
self.students = []
class School:
def __init__(self):
self.groups =[]
наша задача (узнать среднюю оценку учеников) хорошо ложится на модель школы, поэтому этот метод мы и реализуем в школе
class School:
def __init__(self):
self.groups =[]
def get_avg_rate(self):
"""some calculations"""
return
Как видите модели школы абсолютно все равно, откуда в ней возьмутся данные о классах и учениках, мы можем уже сейчас тестировать эту модель. Но нам надо все-таки подойти ближе к xml. И мы пишем класс, который… Нихрена, мы делаем абстрактный базовый класс, который представляет источник данных как таковой. Что нам нужно от источника данных? Чтобы он нам вернул объект класса School, и не важно где он его возьмет.
class AbstactDataSource:
__metaclass__ = ABCMeta
@abstractmethod
def get_school():
pass
Для тестов не связанных с функционированием сети мы можем сделать класс, реализующий наш интерфейс источника данных
class TestDataSource(AbstactDataSource):
def get_school():
school = School()
school.add_group(....)
# etc.
Далее, мы пишем реализацию источника данных на основе XML - XMLDataSource
class XMLDataSource(AbstactDataSource):
def __init__(self, xml):
self.xml = xml
def get_school():
# parse xml here
и класс, который будет откуда-то получать XML-ку для источника данных
class SoapClient:
def __init__(self, url):
self.url = url
def get_xml():
""" get data from url"""
return xml_text
теперь собираем все вместе
class SchoolAnalizer:
url = "http://school.ru/soap"
def __init__(self):
self.datasource = None
def set_datasource(self, datasource = None):
if datasource:
self.datasource = datasource
else:
client = SoapClient(self.url)
self.datasource = XMLDataSource(client.get_xml())
def get_avg_rate(self):
school = self.datasource.get_school()
return school.get_avg_rate()
Каждый из этих компонентов вы можете протестировать самостоятельно и независимо. Ну или в сборе, передавая в методы установки нужные компоненты.
def test_analizer(self):
with open("test.xml", "r") as xml:
data = xml.read()
ds = XMLDataSource(data)
analizer = SchoolAnalizer()
analizer.set_datasource(ds)
assert analizer.get_avg_rate() == 4.56