corebuilder — Setup devilry core data structures for tests¶
Deprecated since version 3.0: See How to unit-test Devilry.
devilry.project.develop.testhelpers.corebuilder is a module that makes it easy to create devilry.apps.core.models data for
tests.
When to use¶
Use this for end-to-end tests and tests where you really need real data. Always try to mock objects instead of creating real data unless you are actually testing something that needs real data.
Howto¶
Each class in the core has a wrapper class in
devilry.project.develop.testhelpers.corebuilder that makes it easy to perform
operations that we need to setup tests. We call these wrappers builders, and
they are all prefixed with the name of their corresponding core model and
suffixed with Builder.
Using the builders is very easy:
from devilry.project.develop.testhelpers.corebuilder import NodeBuilder
duck1010builder = NodeBuilder('duckuniversity').add_subject('duck1010')
assert(duck1010builder.subject == Subject.objects.get(short_name='duck1010'))
They can all easily be updated with new attributes:
duck1010builder.update(long_name='DUCK1010 - Programming')
assert(duck1010builder.subject.long_name == 'DUCK1010 - Programming')
And they have sane defaults optimized for testing, so you can easily create a
deeply nested core object. This creates the duck1010-subject with an active
period that started 3 months ago and ends in 3 months, with a single assignment
(week1), with a single group, with deadline one week from now with a single
helloworld.txt delivery:
from devilry.project.develop.testhelpers.corebuilder import NodeBuilder
from devilry.project.develop.testhelpers.corebuilder import UserBuilder
peterpan = UserBuilder(username='peterpan')
helloworld_filemetabuilder = NodeBuilder('ducku')\
.add_subject('duck1010')\
.add_6month_active_period('current')\
.add_assignment('week1')\
.add_group(students=[peterpan.user])\
.add_deadline_in_x_weeks(weeks=1)\
.add_delivery()\
.add_filemeta(filename='helloworld.txt', data='Hello world')
Since we often need to add a single subject or a single active period, we have shortcuts for that:
from devilry.project.develop.testhelpers.corebuilder import SubjectBuilder
from devilry.project.develop.testhelpers.corebuilder import PeriodBuilder
duck1010_builder = SubjectBuilder.quickadd_ducku_duck1010()
currentperiod_builder = PeriodBuilder.quickadd_ducku_duck1010_active()
Note
These shortcuts is not there just to save a couple of keystrokes. They are there to make sure we use a uniform test setup in 98% of our tests. As long as you just need a single subject or period, you MUST use these shortcuts (to get a patch accepted in Devilry).
Magic and defaults¶
The builders have very little magic, but they have some defaults that make sense when testing:
long_nameis set toshort_namewhen it is not specified explicitly.All BaseNodes (the models with short and long name) takes the
short_nameas the first argument and thelong_nameas the second argument.Time of delivery (for
DeliveryBuilderandDealdineBuilder.add_delivery()) default to now.Default
publishing_timefor assignments is now.UserBuilder defaults to setting email to
<username>@example.com.
These defaults are all handled in the constructor of their builder-class. All the defaults can be overridden by specifying a value for them.
Reload from DB¶
You often need to create an object that is changed by
the code you are testing, and then check that
the change has made it to the database. All our builders implement
ReloadableDbBuilderInterface which includes
reload_from_db().
ReloadableDbBuilderInterface¶
- class devilry.project.develop.testhelpers.corebuilder.ReloadableDbBuilderInterface¶
All the builders implement this interface.
- update(**attributes)¶
Update the object wrapped by the builder with the given attributes. Saves the object, and reloads it from the database.
- reload_from_db(**attributes)¶
Reloads the object wrapped by the builder from the database. Perfect when you create an object that is changed by the code you are testing, and you want to check that the change has made it to the database.
UserBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.UserBuilder¶
Creates a User object for testing. Also creates the DevilryUserProfile, and methods for editing both the User and the profile.
- __init__(username, full_name=None, email=None)¶
Creates a new User with password set to test, and the
devilry.apps.core.models.DevilryUserProfilecreated.- Parameters:
username – The username of the new user.
full_name – Optional full_name. Defaults to
None.email – Optional email. Defaults to
<username>@example.com.
- update(**attributes)¶
Update the User with the given attributes. Reloads the object from the database.
- update_profile(**attributes)¶
Update the
devilry.apps.core.models.DevilryUserProfilewith the given attributes. Reloads the object from the database.
NodeBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.NodeBuilder¶
- node¶
The
Nodewrapped by this builder.
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Nodewith the given attributes.- Parameters:
short_name – The
short_nameof the Node.long_name – The
long_nameof the Node. Defaults toshort_nameifNone.kwargs – Other arguments for the Node constructor.
- add_node(*args, **kwargs)¶
Adds a childnode to the node.
argsandkwargsare forwarded toNodeBuilderwithkwargs['parentnode']set to thisnode.- Return type:
- add_subject(*args, **kwargs)¶
Adds a subject to the node.
argsandkwargsare forwarded toSubjectBuilderwithkwargs['parentnode']set to thisnode.- Return type:
SubjectBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.SubjectBuilder¶
-
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Subjectwith the given attributes.- Parameters:
short_name – The
short_nameof the Subject.long_name – The
long_nameof the Subject. Defaults toshort_nameifNone.kwargs – Other arguments for the Subject constructor.
- classmethod quickadd_ducku_duck1010()¶
When we need just a single subject, we use this shortcut method instead of writing:
NodeBuilder('ducku').add_subject('duck1010')
This is not just to save a couple of letters, but also to promote a common setup for simple tests.
- add_period(*args, **kwargs)¶
Adds a period to the subject.
argsandkwargsare forwarded toPeriodBuilderwithkwargs['parentnode']set to thissubject.- Return type:
- add_6month_active_period(*args, **kwargs)¶
Shortcut for adding
add_period()withstart_time3*30days ago, andend_timein3*30days.argsandkwargsis forwarded toadd_period, but withstart_timeandend_timeset inkwargs.If no
short_nameis provided, it defaults toactive.- Return type:
- add_6month_lastyear_period(*args, **kwargs)¶
Shortcut for adding
add_period()withstart_time365-30*3days ago, andend_time365+3*30days ago.argsandkwargsis forwarded toadd_period, but withstart_timeandend_timeset inkwargs.If no
short_nameis provided, it defaults tolastyear. :rtype:PeriodBuilder.
- add_6month_nextyear_period(*args, **kwargs)¶
Shortcut for adding
add_period()withstart_timein365-30*3days, andend_timein365+3*30days.argsandkwargsis forwarded toadd_period, but withstart_timeandend_timeset inkwargs.If no
short_nameis provided, it defaults tonextyear.- Return type:
PeriodBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.PeriodBuilder¶
-
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Periodwith the given attributes.- Parameters:
short_name – The
short_nameof the Period.long_name – The
long_nameof the Period. Defaults toshort_nameifNone.kwargs – Other arguments for the Period constructor.
- add_assignment(*args, **kwargs)¶
Adds an assignment to the period.
argsandkwargsare forwarded toAssignmentBuilderwithkwargs['parentnode']set to thisperiod.- Return type:
- classmethod quickadd_ducku_duck1010_active()¶
When we need just a single active period, we use this shortcut method instead of writing:
NodeBuilder('ducku').add_subject('duck1010').add_6month_active_period('current')
This is not just to save a couple of letters, but also to promote a common setup for simple tests.
AssignmentBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.AssignmentBuilder¶
- assignment¶
The
Assignmentwrapped by this builder.
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Assignmentwith the given attributes.- Parameters:
short_name – The
short_nameof the Assignment.long_name – The
long_nameof the Assignment. Defaults toshort_nameifNone.publishing_time – The
publishing_timeof the Assignment. Defaults to now.kwargs – Other arguments for the Assignment constructor.
- add_group(*args, **kwargs)¶
Adds an assignment group to the period.
argsandkwargsare forwarded toAssignmentGroupBuilderwithkwargs['parentnode']set to thisassignment.- Return type:
AssignmentGroupBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.AssignmentGroupBuilder¶
- assignment_group¶
The
AssignmentGroupwrapped by this builder.
- __init__(students=[], candidates=[], examiners=[], **kwargs)¶
Creates a new
AssignmentGroupwith the given attributes.- Parameters:
students – Forwarded to
add_students().candidates – Forwarded to
add_candidates().examiners – Forwarded to
add_examiners().kwargs – Arguments for the AssignmentGroup constructor.
- add_students(*users)¶
Add the given users as candidates without a candidate ID on this assignment group.
- Returns:
self(to enable us to nest the method call).
- add_examiners(*users)¶
Add the given users as examiners on this assignment group.
- Returns:
self(to enable us to nest the method call).
- add_students(*candidates)¶
Add the given candidates to this assignment group.
- Parameters:
candidates –
devilry.apps.core.models.Candidateobjects.- Returns:
self(to enable us to nest the method call).
- add_deadline(*args, **kwargs)¶
Adds an deadline to the assignment.
argsandkwargsare forwarded toDeadlineBuilderwithkwargs['assignment_group']set to thisassignment_group.- Return type:
- add_deadline_in_x_weeks(weeks, *args, **kwargs)¶
Calls
add_deadline()withkwargs[deadline]setweeksweeks in the future.- Return type:
- add_deadline_x_weeks_ago(weeks, *args, **kwargs)¶
Calls
add_deadline()withkwargs[deadline]setweeksweeks in the past.- Return type:
DeadlineBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.DeadlineBuilder¶
- deadline¶
The
Deadlinewrapped by this builder.
- __init__(**kwargs)¶
Creates a new
AssignmentGroupwith the given attributes.- Parameters:
kwargs – Arguments for the Deadline constructor.
- add_delivery(**kwargs)¶
Adds a delivery to the deadline.
argsandkwargsare forwarded toDeliveryBuilderwithkwargs['deadline']set to thisdeadlineandkwargs['successful']defaulting toTrue.- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilderconstructor.- Return type:
- add_delivery_after_deadline(timedeltaobject, **kwargs)¶
Add a delivery
timedeltaobjecttime after this deadline expires.Shortcut that calls
add_delivery()withkwargs['time_of_delivery']set todeadline.deadline + timedeltaobject.Example - add delivery 3 weeks and 2 hours after deadline:
from datetime import datetime, timedelta deadlinebuilder = DeadlineBuilder(deadline=datetime(2010, 1, 1)) deadlinebuilder.add_delivery_after_deadline(timedelta(weeks=3, hours=2))
- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilderconstructor.- Return type:
- add_delivery_before_deadline(timedeltaobject, **kwargs)¶
Add a delivery
timedeltaobjecttime before this deadline expires.Shortcut that calls
add_delivery()withkwargs['time_of_delivery']set todeadline.deadline + timedeltaobject.Example - add delivery 5 hours before deadline:
from datetime import datetime, timedelta deadlinebuilder = DeadlineBuilder(deadline=datetime(2010, 1, 1)) deadlinebuilder.add_delivery_before_deadline(timedelta(hours=5))
- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilderconstructor.- Return type:
- add_delivery_x_hours_after_deadline(timedeltaobject, **kwargs)¶
Add a delivery
hourshours after this deadline expires.Shortcut that calls
add_delivery_after_deadline()with timedeltaobject set totimedelta(hours=hours).- Parameters:
hours – Number of hours.
kwargs – Extra kwargs for the
DeliveryBuilderconstructor.
- Return type:
- add_delivery_x_hours_before_deadline(timedeltaobject, **kwargs)¶
Add a delivery
hourshours before this deadline expires.Shortcut that calls
add_delivery_before_deadline()with timedeltaobject set totimedelta(hours=hours).- Parameters:
hours – Number of hours.
kwargs – Extra kwargs for the
DeliveryBuilderconstructor.
- Return type:
DeliveryBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.DeliveryBuilder¶
- delivery¶
The
Deliverywrapped by this builder.
- __init__(**kwargs)¶
Creates a new
Deliverywith the given attributes. Iftime_of_deliveryis not provided, it defaults to now.- Parameters:
kwargs – Arguments for the Delivery constructor.
- add_filemeta(**kwargs)¶
Adds a filemeta to the delivery.
kwargsis forwarded toFilteMetaBuilderwithkwargs['delivery']set to thisdelivery.Example:
deliverybuilder.add_filemeta( filename='test.txt', data='This is a test.' )
- Parameters:
kwargs – Kwargs for the
FileMetaBuilderconstructor.- Return type:
- add_feedback(**kwargs)¶
Adds a feedback to the delivery.
kwargsis forwarded toStaticFeedbackBuilderwithkwargs['delivery']set to thisdelivery.Example:
deliverybuilder.add_feedback( points=10, grade='10/100', is_passing_grade=False, saved_by=UserBuilder('testuser').user )
- Parameters:
kwargs – Kwargs for the
StaticFeedbackBuilderconstructor.- Return type:
- add_passed_feedback(**kwargs)¶
Shortcut that adds a passed feedback to the delivery.
kwargsis forwarded toadd_feedback()with:points=1grade="Passed"is_passing_grade=True
Example:
deliverybuilder.add_passed_feedback(saved_by=UserBuilder('testuser').user)
- Parameters:
kwargs – Extra kwargs for
add_feedback(). Is updated with :points, grade and is_passing_grade as documented above.- Return type:
- add_failed_feedback(**kwargs)¶
Shortcut that adds a failed feedback to the delivery.
kwargsis forwarded toadd_feedback()with:points=0grade="Failed"is_passing_grade=False
Example:
deliverybuilder.add_failed_feedback(saved_by=UserBuilder('testuser').user)
- Parameters:
kwargs – Extra kwargs for
add_feedback(). Is updated with :points, grade and is_passing_grade as documented above.- Return type:
FileMetaBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.FileMetaBuilder¶
- filemeta¶
The
FileMetawrapped by this builder.
- __init__(delivery, filename, data)¶
Creates a new
FileMeta. Since FileMeta just points to files on disk, and creating those files requires iterators and extra stuff that is almost never needed for tests, we provide an easier method for creating files with FileMetaBuilder.- Parameters:
delivery – The Delivery object.
filename – A filename.
data – The file contents as a string.