示例 A-12 是 schedule1.py 模块(示例 19-9)的测试脚本,使用 py.test 库和测试运行程序实现。
示例 A-12 test_schedule1.py
import shelve
import pytest
import schedule1 as schedule
@pytest.yield_fixture
def db():
with shelve.open(schedule.DB_NAME) as the_db:
if schedule.CONFERENCE not in the_db:
schedule.load_db(the_db)
yield the_db
def test_record_class():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_conference_record(db):
assert schedule.CONFERENCE in db
def test_speaker_record(db):
speaker = db['speaker.3471']
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_event_record(db):
event = db['event.33950']
assert event.name == 'There *Will* Be Bugs'
def test_event_venue(db):
event = db['event.33950']
assert event.venue_serial == 1449
19.1.5 节分四部分列出了 schedule2.py 脚本里的代码,示例 A-13 是完整的代码清单。
示例 A-13 schedule2.py
"""
schedule2.py: 遍历OSCON的日程数据
>>> import shelve
>>> db = shelve.open(DB_NAME)
>>> if CONFERENCE not in db: load_db(db)
# BEGIN SCHEDULE2_DEMO
>>> DbRecord.set_db(db)
>>> event = DbRecord.fetch('event.33950')
>>> event
<Event 'There *Will* Be Bugs'>
>>> event.venue
<DbRecord serial='venue.1449'>
>>> event.venue.name
'Portland 251'
>>> for spkr in event.speakers:
... print('{0.serial}: {0.name}'.format(spkr))
...
speaker.3471: Anna Martelli Ravenscroft
speaker.5199: Alex Martelli
# END SCHEDULE2_DEMO
>>> db.close()
"""
# BEGIN SCHEDULE2_RECORD
import warnings
import inspect
import osconfeed
DB_NAME = 'data/schedule2_db'
CONFERENCE = 'conference.115'
class Record:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __eq__(self, other):
if isinstance(other, Record):
return self.__dict__ == other.__dict__
else:
return NotImplemented
# END SCHEDULE2_RECORD
# BEGIN SCHEDULE2_DBRECORD
class MissingDatabaseError(RuntimeError):
"""Raised when a database is required but was not set."""
class DbRecord(Record):
__db = None
@staticmethod
def set_db(db):
DbRecord.__db = db
@staticmethod
def get_db():
return DbRecord.__db
@classmethod
def fetch(cls, ident):
db = cls.get_db()
try:
return db[ident]
except TypeError:
if db is None:
msg = "database not set; call '{}.set_db(my_db)'"
raise MissingDatabaseError(msg.format(cls.__name__))
else:
raise
def __repr__(self):
if hasattr(self, 'serial'):
cls_name = self.__class__.__name__
return '<{} serial={!r}>'.format(cls_name, self.serial)
else:
return super().__repr__()
# END SCHEDULE2_DBRECORD
# BEGIN SCHEDULE2_EVENT
class Event(DbRecord):
@property
def venue(self):
key = 'venue.{}'.format(self.venue_serial)
return self.__class__.fetch(key)
@property
def speakers(self):
if not hasattr(self, '_speaker_objs'):
spkr_serials = self.__dict__['speakers']
fetch = self.__class__.fetch
self._speaker_objs = [fetch('speaker.{}'.format(key))
for key in spkr_serials]
return self._speaker_objs
def __repr__(self):
if hasattr(self, 'name'):
cls_name = self.__class__.__name__
return '<{} {!r}>'.format(cls_name, self.name)
else:
return super().__repr__()
# END SCHEDULE2_EVENT
# BEGIN SCHEDULE2_LOAD
def load_db(db):
raw_data = osconfeed.load()
warnings.warn('loading ' + DB_NAME)
for collection, rec_list in raw_data['Schedule'].items():
record_type = collection[:-1]
cls_name = record_type.capitalize()
cls = globals().get(cls_name, DbRecord)
if inspect.isclass(cls) and issubclass(cls, DbRecord):
factory = cls
else:
factory = DbRecord
for record in rec_list:
key = '{}.{}'.format(record_type, record['serial'])
record['serial'] = key
db[key] = factory(**record)
# END SCHEDULE2_LOAD
示例 A-14 使用 py.test 测试示例 A-13。
示例 A-14 test_schedule2.py
import shelve
import pytest
import schedule2 as schedule
@pytest.yield_fixture
def db():
with shelve.open(schedule.DB_NAME) as the_db:
if schedule.CONFERENCE not in the_db:
schedule.load_db(the_db)
yield the_db
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_record_repr():
rec = schedule.DbRecord(spam=99, eggs=12)
assert 'DbRecord object at 0x' in repr(rec)
rec2 = schedule.DbRecord(serial=13)
assert repr(rec2) == "<DbRecord serial=13>"
def test_conference_record(db):
assert schedule.CONFERENCE in db
def test_speaker_record(db):
speaker = db['speaker.3471']
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_missing_db_exception():
with pytest.raises(schedule.MissingDatabaseError):
schedule.DbRecord.fetch('venue.1585')
def test_dbrecord(db):
schedule.DbRecord.set_db(db)
venue = schedule.DbRecord.fetch('venue.1585')
assert venue.name == 'Exhibit Hall B'
def test_event_record(db):
event = db['event.33950']
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
def test_event_venue(db):
schedule.Event.set_db(db)
event = db['event.33950']
assert event.venue_serial == 1449
assert event.venue == db['venue.1449']
assert event.venue.name == 'Portland 251'
def test_event_speakers(db):
schedule.Event.set_db(db)
event = db['event.33950']
assert len(event.speakers) == 2
anna_and_alex = [db['speaker.3471'], db['speaker.5199']]
assert event.speakers == anna_and_alex
def test_event_no_speakers(db):
schedule.Event.set_db(db)
event = db['event.36848']
assert len(event.speakers) == 0