devilry.apps.core.testhelper — Create core test data

Deprecated since version 1.4: Use corebuilder — Setup devilry core data structures for tests instead.

Example

from devilry.apps.core.testhelper import TestHelper

testhelper = TestHelper()

testhelper.add(nodes='uni:admin(mortend)',
         subjects=['cs101:admin(admin1,admin2):ln(Basic OO programming)',
                   'cs110:admin(admin3,admin4):ln(Basic scientific programming)',
                   'cs111:admin(admin1,damin3):ln(Advanced OO programming)'],
         periods=['fall11', 'spring11:begins(6)'])

# add 4 assignments to inf101 and inf110 in fall and spring
testhelper.add(nodes='uni',
         subjects=['cs101', 'cs110'],
         periods=['fall11', 'spring11'],
         assignments=['a1', 'a2'])

# add 12 assignments to inf111 fall and spring.
testhelper.add(nodes='uni',
         subjects=['cs111'],
         periods=['fall11', 'spring11'],
         assignments=['week1', 'week2', 'week3', 'week4'])

# set up some students with descriptive names

# inf101 is so easy, everyone passes
testhelper.add_to_path('uni;cs101.fall11.a1.g1:candidate(goodStud1):examiner(examiner1).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a1.g2:candidate(goodStud2):examiner(examiner1).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a1.g3:candidate(badStud3):examiner(examiner2).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a1.g4:candidate(okStud4):examiner(examiner2).dl:ends(5)')

testhelper.add_to_path('uni;cs101.fall11.a2.g1:candidate(goodStud1):examiner(examiner1).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a2.g2:candidate(goodStud2):examiner(examiner1).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a2.g3:candidate(badStud3):examiner(examiner2).dl:ends(5)')
testhelper.add_to_path('uni;cs101.fall11.a2.g4:candidate(okStud4):examiner(examiner2).dl:ends(5)')

# inf110 is an easy group-project, everyone passes
testhelper.add_to_path('uni;cs110.fall11.a1.g1:candidate(goodStud1,goodStud2):examiner(examiner1).dl:ends(14)')
testhelper.add_to_path('uni;cs110.fall11.a1.g2:candidate(badStud3,okStud4):examiner(examiner2).dl.ends(14)')

testhelper.add_to_path('uni;cs110.fall11.a2.g1:candidate(goodStud1,goodStud2):examiner(examiner1).dl:ends(14)')
testhelper.add_to_path('uni;cs110.fall11.a2.g2:candidate(badStud3,okStud4):examiner(examiner2).dl.ends(14)')

# inf111 is hard! Everyone passes week1
testhelper.add_to_path('uni;cs111.fall11.week1.g1:candidate(goodStud1):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week1.g2:candidate(goodStud2):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week1.g3:candidate(badStud3):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week1.g4:candidate(okStud4):examiner(examiner3).dl:ends(5)')

# and 2
testhelper.add_to_path('uni;cs111.fall11.week2.g1:candidate(goodStud1):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week2.g2:candidate(goodStud2):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week2.g3:candidate(badStud3):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week2.g4:candidate(okStud4):examiner(examiner3).dl:ends(5)')

# badStud4 fails at week3
testhelper.add_to_path('uni;cs111.fall11.week3.g1:candidate(goodStud1):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week3.g2:candidate(goodStud2):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week3.g4:candidate(okStud2):examiner(examiner3).dl:ends(5)')

# and okStud4 fails at week4
testhelper.add_to_path('uni;cs111.fall11.week4.g1:candidate(goodStud1):examiner(examiner3).dl:ends(5)')
testhelper.add_to_path('uni;cs111.fall11.week4.g2:candidate(goodStud2):examiner(examiner3).dl:ends(5)')

# deliveries
goodFile = {'good.py': ['print ', 'awesome']}
okFile = {'ok.py': ['print ', 'meh']}
badFile = {'bad.py': ['print ', 'bah']}

# cs101
testhelper.add_delivery('cs101.fall11.a1.g1', goodFile)
testhelper.add_delivery('cs101.fall11.a1.g2', goodFile)
testhelper.add_delivery('cs101.fall11.a1.g3', badFile)
testhelper.add_delivery('cs101.fall11.a1.g4', okFile)
testhelper.add_delivery('cs101.fall11.a2.g1', goodFile)
testhelper.add_delivery('cs101.fall11.a2.g2', goodFile)
testhelper.add_delivery('cs101.fall11.a2.g3', badFile)
testhelper.add_delivery('cs101.fall11.a2.g4', okFile)

# cs110
testhelper.add_delivery('cs110.fall11.a1.g1', goodFile)
testhelper.add_delivery('cs110.fall11.a1.g1', goodFile)
testhelper.add_delivery('cs110.fall11.a2.g2', badFile)
testhelper.add_delivery('cs110.fall11.a2.g2', okFile)

# cs111
testhelper.add_delivery('cs111.fall11.week1.g1', goodFile)
testhelper.add_delivery('cs111.fall11.week1.g2', goodFile)
testhelper.add_delivery('cs111.fall11.week1.g3', badFile)
testhelper.add_delivery('cs111.fall11.week1.g4', okFile)

# g3's delivery fails here
testhelper.add_delivery('cs111.fall11.week2.g1', goodFile)
testhelper.add_delivery('cs111.fall11.week2.g2', goodFile)
testhelper.add_delivery('cs111.fall11.week2.g3', badFile)
testhelper.add_delivery('cs111.fall11.week2.g4', okFile)

# g4's delivery fails here
testhelper.add_delivery('cs111.fall11.week3.g1', goodFile)
testhelper.add_delivery('cs111.fall11.week3.g2', goodFile)
testhelper.add_delivery('cs111.fall11.week3.g4', okFile)

# g4 fails
testhelper.add_delivery('cs111.fall11.week4.g1', goodFile)
testhelper.add_delivery('cs111.fall11.week4.g2', goodFile)

# feedbacks
#   an empty verdict defaults to max score
goodVerdict = None
okVerdict = {'grade': 'C', 'points': 85, 'is_passing_grade': True}
badVerdict = {'grade': 'E', 'points': 60, 'is_passing_grade': True}
failVerdict = {'grade': 'F', 'points': 30, 'is_passing_grade': False}

testhelper.add_feedback('cs101.fall11.a1.g1', verdict=goodVerdict)
testhelper.add_feedback('cs101.fall11.a1.g2', verdict=goodVerdict)
testhelper.add_feedback('cs101.fall11.a1.g3', verdict=badVerdict)
testhelper.add_feedback('cs101.fall11.a1.g4', verdict=okVerdict)
testhelper.add_feedback('cs101.fall11.a2.g1', verdict=goodVerdict)
testhelper.add_feedback('cs101.fall11.a2.g2', verdict=goodVerdict)
testhelper.add_feedback('cs101.fall11.a2.g3', verdict=badVerdict)
testhelper.add_feedback('cs101.fall11.a2.g4', verdict=okVerdict)

# cs110
testhelper.add_feedback('cs110.fall11.a1.g1', verdict=goodVerdict)
testhelper.add_feedback('cs110.fall11.a1.g1', verdict=badVerdict)
testhelper.add_feedback('cs110.fall11.a2.g2', verdict=goodVerdict)
testhelper.add_feedback('cs110.fall11.a2.g2', verdict=okVerdict)

# cs111
testhelper.add_feedback('cs111.fall11.week1.g1', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week1.g2', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week1.g3', verdict=badVerdict)
testhelper.add_feedback('cs111.fall11.week1.g4', verdict=okVerdict)

# g3's feedback fails here
testhelper.add_feedback('cs111.fall11.week2.g1', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week2.g2', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week2.g3', verdict=failVerdict)
testhelper.add_feedback('cs111.fall11.week2.g4', verdict=okVerdict)

# g4's feedback fails here
testhelper.add_feedback('cs111.fall11.week3.g1', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week3.g2', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week3.g4', verdict=failVerdict)

# g4 fails
testhelper.add_feedback('cs111.fall11.week4.g1', verdict=goodVerdict)
testhelper.add_feedback('cs111.fall11.week4.g2', verdict=goodVerdict)

TestHelper API

class devilry.apps.core.testhelper.TestHelper

Bases: object

This class helps generate test data.

create_user(name, fullname=None)

Create a user with the given username. Adds the user to self.<name>.

Returns:The created user object.
reload_from_db(obj)

Reload the given django.db.Model object from the database using obj.__class__.get(pk=obj.pk). Updates the cache entry on this testhelper object if the object was created using this testhelper.

Returns:The object that was re-loaded from the database.
create_superuser(name)

Create a superuser with the given username. Adds the user to self.<name>.

Returns:The created user object.
add_delivery(assignmentgroup, files={}, after_last_deadline=False, delivered_by=None, successful=True, time_of_delivery=None)
Parameters:
  • assignmentgroup – Expects either an AssignmentGroup object or a string path to an assignmentgroup. This is a mandatory parameter.
  • files – A dictionary with key/values as file name and file content as described in Delivery.add_file()
  • after_last_deadline – If True, sets time_of_delivery 1 day later than the assignmentgroups active deadline. Effectively the same as setting time_of_delivery=1. Ignored i time_of_delivery is used.
  • time_of_delivery – Set time_of_delivery to this number of days after the active deadline. Use a negative number to add a delivery before the active deadline. Can also be a datetime.datetime object that specifies an exact timestamp.
add_feedback(delivery=None, verdict=None, examiner=None, timestamp=None, rendered_view='This is a default static feedback')
Parameters:
  • delivery – Either a Delivery object or a string path to an assignmentgroup, where we take the last delivery made. This is the only mandatory parameter
  • verdict

    E dict containing grade, score and passing grade. Defaults to:

    dict(grade='A', points=100, is_passing_grade=True)
    
  • examiner – A User object. Defaults to the first examiner for the delivery’s assignment group.
  • timestamp – A datetime object for when the feedback was saved. Defaults to same time the delivery was made
  • rendered_view – The rendered view of the feedback. Defaults to "This is a default static feedback".
add(nodes=None, subjects=None, periods=None, assignments=None, assignmentgroups=None, deadlines=None)

Smart add.

Each attribute is normally just a list of names. The names are short_name, for nodeish types, and a virtual name for assignmentgroups, and deadlines.

Names can be supplemented by extras, which are parameters that tunes the created items. Extras are separated by colon (:), and each extra has the following format:

<name>(<args>)
Parameters:
  • nodes

    List of nodes.

    admin
    Comma-separated list of admins (usernames) to add to the node.
    ln
    Long name of the period. Defaults to capitalize short name.
  • subjects

    List of subjects. Extras:

    admin
    Comma-separated list of admins (usernames) to add to the node.
    ln
    Long name of the period. Defaults to capitalize short name.
  • periods

    List of nodes. Extras:

    admin
    Comma-separated list of admins (usernames) to add to the node.
    ln
    Long name of the period. Defaults to capitalize short name.
    begins
    Number of months after now that the period begins. Can be a negative number. Defaults to now.
    ends
    Number of months after begins that the period ends. Can be a negative number. Defaults to 6.
  • assignments

    List of assignments.

    admin
    Comma-separated list of admins (usernames) to add to the node.
    ln
    Long name of the period. Defaults to capitalize short name.
    anon
    Should the assignment be anonymous? true or false, and defaults to false.
    pub
    Number of days after the start time of the period that the assignment should be published. Can be a negative number. Defaults to 0.
    delivery_types
    electronic or nonelectronic.
    first_deadline
    The offset of the first_deadline from the publishing_time in days. If this is 0, we automatically add 1 second to the publishing_time to ensure that they are not equal.
  • assignmentgroups

    List of assignmentgroups. Extras:

    candidate
    Comma-separated list of candidates (usernames) to add to the group. Optionally, you can add a candidate_id by suffixing the username with ;<candidate_id>. Example: candidate(student0;2345,student1;5673)
    examiner
    Comma-separated list of examiners (usernames) to add to the group.
  • deadlines

    List of deadlines. Extras:

    ends
    Number of days after the publishing_time of the deadline ends. Can be a negative number. Defaults to 10 days.
    text
    Deadline text.
add_to_path(path)

Splits up a dot separated path, and calls add() with those pieces as arguments.

get_object_from_path(path)

Get a Node, Subject, Period, Assignment, AssignmentGroup, Deadline, Delivery or Feedback that was added with add(), add_feedback(), add_to_path(), or add_delivery().

The path does not have to contain the node path (unless you are looking up a node), since subject shortnames are unique.

set_attributes_from_path(path, **attributes)

Shortcut to get_object_from_path(), set the given attributes on the object, and call obj.save().

create_feedbacks(*args)

Create feedbacks on groups from the given list of (group, feedback, delivery)-tuples.

Parameters:args

Each item in the arguments list is a (group, feedback[, delivery]) tuple where:

group
is the devilry.apps.core.models.AssignmentGroup-object that it to be given feedback
feedbacks
is a dict with attributes for the devilry.apps.core.models.StaticFeedback with the following keys:
grade
See devilry.apps.core.models.StaticFeedback.grade.
points
See devilry.apps.core.models.StaticFeedback.points.
is_passing_grade
See devilry.apps.core.models.StaticFeedback.is_passing_grade.
delivery
Is an optional dict of files to make a delivery from. Defaults to:
{'test.py': ['print ', 'tst']}

A delivery to save the feedback on is created automatically, so all that is needed of the groups is an examiner, a candidate and a deadline.

Example:

self.create_feedbacks(
    (group1, {'grade': 'B', 'points': 86, 'is_passing_grade': True}),
    (group2, {'grade': 'A', 'points': 96, 'is_passing_grade': True}, {'hello.txt', ['Hello']}),
    (group3, {'grade': 'F', 'points': 12, 'is_passing_grade': False})
)