Merge branch 'MDL-62446-master' of git://github.com/lameze/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 12 Jun 2018 16:21:40 +0000 (18:21 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 12 Jun 2018 16:21:40 +0000 (18:21 +0200)
41 files changed:
admin/tool/dataprivacy/classes/task/initiate_data_request_task.php
admin/tool/dataprivacy/classes/task/process_data_request_task.php
admin/tool/dataprivacy/createdatarequest_form.php
backup/util/ui/backup_ui_stage.class.php
backup/util/ui/base_moodleform.class.php
backup/util/ui/renderer.php
course/classes/management_renderer.php
lang/en/backup.php
lib/filestorage/stored_file.php
lib/navigationlib.php
lib/phpunit/classes/hint_resultprinter.php
lib/testing/generator/data_generator.php
mod/assign/feedback/comments/tests/comments_test.php
mod/assign/feedback/editpdf/tests/editpdf_test.php
mod/assign/feedback/file/tests/file_test.php
mod/assign/submission/comments/tests/events_test.php
mod/assign/submission/file/tests/events_test.php
mod/assign/submission/file/tests/locallib_test.php
mod/assign/submission/onlinetext/tests/events_test.php
mod/assign/submission/onlinetext/tests/locallib_test.php
mod/assign/tests/base_test.php
mod/assign/tests/events_test.php
mod/assign/tests/externallib_test.php
mod/assign/tests/fixtures/testable_assign.php [new file with mode: 0644]
mod/assign/tests/generator.php [new file with mode: 0644]
mod/assign/tests/lib_test.php
mod/assign/tests/locallib_test.php
mod/assign/tests/portfolio_caller_test.php
mod/assign/tests/restore_date_test.php
mod/assign/tests/search_test.php
mod/assign/tests/upgradelib_test.php
mod/assign/upgrade.txt
mod/chat/lib.php
mod/chat/locallib.php
mod/chat/tests/externallib_test.php
mod/chat/tests/lib_test.php
mod/folder/renderer.php
privacy/classes/local/request/contextlist_base.php
privacy/tests/contextlist_base_test.php
question/type/multianswer/renderer.php
theme/boost/scss/moodle/course.scss

index 2ee4a0a..70402f4 100644 (file)
@@ -54,7 +54,7 @@ class initiate_data_request_task extends adhoc_task {
     public function execute() {
         global $CFG;
 
-        require_once($CFG->dirroot . '/admin/tool/dataprivacy/lib.php');
+        require_once($CFG->dirroot . "/{$CFG->admin}/tool/dataprivacy/lib.php");
 
         if (!isset($this->get_custom_data()->requestid)) {
             throw new coding_exception('The custom data \'requestid\' is required.');
index 6a93217..c58f574 100644 (file)
@@ -57,7 +57,7 @@ class process_data_request_task extends adhoc_task {
     public function execute() {
         global $CFG, $PAGE, $SITE;
 
-        require_once($CFG->dirroot . '/admin/tool/dataprivacy/lib.php');
+        require_once($CFG->dirroot . "/{$CFG->admin}/tool/dataprivacy/lib.php");
 
         if (!isset($this->get_custom_data()->requestid)) {
             throw new coding_exception('The custom data \'requestid\' is required.');
index 680b93a..4c94a8a 100644 (file)
@@ -44,19 +44,28 @@ class tool_dataprivacy_data_request_form extends moodleform {
     /**
      * Form definition.
      *
-     * @throws HTML_QuickForm_Error
      * @throws coding_exception
-     * @throws dml_exception
      */
     public function definition() {
-        global $DB, $USER;
+        global $USER;
         $mform =& $this->_form;
 
         $this->manage = $this->_customdata['manage'];
         if ($this->manage) {
             $options = [
                 'ajax' => 'tool_dataprivacy/form-user-selector',
-                'multiple' => false
+                'valuehtmlcallback' => function($value) {
+                    global $OUTPUT;
+
+                    $allusernames = get_all_user_name_fields(true);
+                    $fields = 'id, email, ' . $allusernames;
+                    $user = \core_user::get_user($value, $fields);
+                    $useroptiondata = [
+                        'fullname' => fullname($user),
+                        'email' => $user->email
+                    ];
+                    return $OUTPUT->render_from_template('tool_dataprivacy/form-user-selector-suggestion', $useroptiondata);
+                }
             ];
             $mform->addElement('autocomplete', 'userid', get_string('requestfor', 'tool_dataprivacy'), [], $options);
             $mform->addRule('userid', null, 'required', null, 'client');
index ec1b3b1..1e1caf8 100644 (file)
@@ -183,7 +183,11 @@ class backup_ui_stage_initial extends backup_ui_stage {
             foreach ($tasks as &$task) {
                 // For the initial stage we are only interested in the root settings.
                 if ($task instanceof backup_root_task) {
-                    $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                    if ($this->ui instanceof import_ui) {
+                        $form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
+                    } else {
+                        $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                    }
                     $settings = $task->get_settings();
                     // First add all settings except the filename setting.
                     foreach ($settings as &$setting) {
@@ -469,7 +473,11 @@ class backup_ui_stage_confirmation extends backup_ui_stage {
             foreach ($tasks as $task) {
                 if ($task instanceof backup_root_task) {
                     // If its a backup root add a root settings heading to group nicely.
-                    $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                    if ($this->ui instanceof import_ui) {
+                        $form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
+                    } else {
+                        $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                    }
                 } else if (!$courseheading) {
                     // We haven't already add a course heading.
                     $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
index 4685a66..32ac8fb 100644 (file)
@@ -383,7 +383,13 @@ abstract class base_moodleform extends moodleform {
         $this->require_definition_after_data();
 
         $config = new stdClass;
-        $config->title = get_string('confirmcancel', 'backup');
+        if ($this->uistage->get_ui() instanceof import_ui) {
+            $config->title = get_string('confirmcancelimport', 'backup');
+        } else if ($this->uistage->get_ui() instanceof restore_ui) {
+            $config->title = get_string('confirmcancelrestore', 'backup');
+        } else {
+            $config->title = get_string('confirmcancel', 'backup');
+        }
         $config->question = get_string('confirmcancelquestion', 'backup');
         $config->yesLabel = get_string('confirmcancelyes', 'backup');
         $config->noLabel = get_string('confirmcancelno', 'backup');
index f656577..23462cf 100644 (file)
@@ -125,7 +125,13 @@ class core_backup_renderer extends plugin_renderer_base {
         $html .= html_writer::end_tag('div');
 
         $html .= html_writer::start_tag('div', array('class' => 'backup-section settings-section'));
-        $html .= $this->output->heading(get_string('backupsettings', 'backup'), 2, array('class' => 'header'));
+        if ($this instanceof import_ui_stage_inital) {
+            $html .= $this->output->heading(get_string('importrootsettings', 'backup'), 2, array('class' => 'header'));
+        } else if ($this instanceof restore_ui_stage_settings) {
+            $html .= $this->output->heading(get_string('restorerootsettings', 'backup'), 2, array('class' => 'header'));
+        } else {
+            $html .= $this->output->heading(get_string('backupsettings', 'backup'), 2, array('class' => 'header'));
+        }
         foreach ($details->root_settings as $label => $value) {
             if ($label == 'filename' or $label == 'user_files') {
                 continue;
index f66cd8c..4390d5a 100644 (file)
@@ -139,7 +139,7 @@ class core_course_management_renderer extends plugin_renderer_base {
         $listing = coursecat::get(0)->get_children();
 
         $attributes = array(
-            'class' => 'ml-1',
+            'class' => 'ml',
             'role' => 'tree',
             'aria-labelledby' => 'category-listing-title'
         );
@@ -530,7 +530,7 @@ class core_course_management_renderer extends plugin_renderer_base {
             array('id' => 'course-listing-title', 'tabindex' => '0'));
         $html .= $this->course_listing_actions($category, $course, $perpage);
         $html .= $this->listing_pagination($category, $page, $perpage, false, $viewmode);
-        $html .= html_writer::start_tag('ul', array('class' => 'ml-1 course-list', 'role' => 'group'));
+        $html .= html_writer::start_tag('ul', array('class' => 'ml course-list', 'role' => 'group'));
         foreach ($category->get_courses($options) as $listitem) {
             $html .= $this->course_listitem($category, $listitem, $courseid);
         }
@@ -1117,7 +1117,7 @@ class core_course_management_renderer extends plugin_renderer_base {
         ));
         $html .= html_writer::tag('h3', get_string('courses'));
         $html .= $this->search_pagination($totalcourses, $page, $perpage);
-        $html .= html_writer::start_tag('ul', array('class' => 'ml-1'));
+        $html .= html_writer::start_tag('ul', array('class' => 'ml'));
         foreach ($courses as $listitem) {
             $i++;
             if ($i == $totalcourses) {
index e9f514b..dc711e8 100644 (file)
@@ -120,6 +120,8 @@ $string['configrestoreroleassignments'] = 'If enabled by default roles assignmen
 $string['configrestoreuserscompletion'] = 'If enabled user completion information will be restored by default if it was included in the backup.';
 $string['configrestoreusers'] = 'Sets the default for whether to restore users if they were included in the backup.';
 $string['confirmcancel'] = 'Cancel backup';
+$string['confirmcancelrestore'] = 'Cancel restore';
+$string['confirmcancelimport'] = 'Cancel import';
 $string['confirmcancelquestion'] = 'Are you sure you wish to cancel?
 Any information you have entered will be lost.';
 $string['confirmcancelyes'] = 'Cancel';
@@ -198,6 +200,7 @@ $string['importcurrentstage2'] = 'Schema settings';
 $string['importcurrentstage4'] = 'Confirmation and review';
 $string['importcurrentstage8'] = 'Perform import';
 $string['importcurrentstage16'] = 'Complete';
+$string['importrootsettings'] = 'Import settings';
 $string['importsettings'] = 'General import settings';
 $string['importsuccess'] = 'Import complete. Click continue to return to the course.';
 $string['includeactivities'] = 'Include:';
index 0f67664..f1c3f75 100644 (file)
@@ -1063,6 +1063,9 @@ class stored_file {
      * @return  string|bool false if a problem occurs, the thumbnail image data otherwise
      */
     public function generate_image_thumbnail($width, $height) {
+        global $CFG;
+        require_once($CFG->libdir . '/gdlib.php');
+
         if (empty($width) or empty($height)) {
             return false;
         }
index b90b9a2..f8208c8 100644 (file)
@@ -3988,6 +3988,7 @@ class settings_navigation extends navigation_node {
         if ($context->contextlevel == CONTEXT_BLOCK) {
             $this->load_block_settings();
             $context = $context->get_parent_context();
+            $this->context = $context;
         }
         switch ($context->contextlevel) {
             case CONTEXT_SYSTEM:
index a21ca51..fb10e5a 100644 (file)
@@ -116,7 +116,7 @@ class Hint_ResultPrinter extends PHPUnit\TextUI\ResultPrinter {
             }
         }
 
-        $this->write("\nTo re-run:\n $executable $testName $file\n");
+        $this->write("\nTo re-run:\n $executable \"$testName\" $file\n");
     }
 }
 
index 5dc5e4c..b52fa58 100644 (file)
@@ -1163,4 +1163,24 @@ EOD;
 
         return $event->properties();
     }
+
+    /**
+     * Create a new user, and enrol them in the specified course as the supplied role.
+     *
+     * @param   \stdClass   $course The course to enrol in
+     * @param   string      $role The role to give within the course
+     * @param   \stdClass   $userparams User parameters
+     * @return  \stdClass   The created user
+     */
+    public function create_and_enrol($course, $role = 'student', $userparams = null, $enrol = 'manual',
+            $timestart = 0, $timeend = 0, $status = null) {
+        global $DB;
+
+        $user = $this->create_user($userparams);
+        $roleid = $DB->get_field('role', 'id', ['shortname' => $role ]);
+
+        $this->enrol_user($user->id, $course->id, $roleid, $enrol, $timestart, $timeend, $status);
+
+        return $user;
+    }
 }
index 8050ca4..8ba047d 100644 (file)
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for assignfeedback_comments
@@ -33,60 +33,54 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  * @copyright  2016 Adrian Greeve <adrian@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assignfeedback_comments_testcase extends mod_assign_base_testcase {
+class assignfeedback_comments_testcase extends advanced_testcase {
 
-    /**
-     * Create an assign object and submit an online text submission.
-     */
-    protected function create_assign_and_submit_text() {
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
-                                               'assignfeedback_comments_enabled' => 1));
-
-        $user = $this->students[0];
-        $this->setUser($user);
-
-        // Create an online text submission.
-        $submission = $assign->get_user_submission($user->id, true);
-
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-                'text' => '<p>This is some text.</p>',
-                'format' => 1,
-                'itemid' => file_get_unused_draft_itemid());
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
-
-        return $assign;
-    }
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test the is_feedback_modified() method for the comments feedback.
      */
     public function test_is_feedback_modified() {
-        $assign = $this->create_assign_and_submit_text();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $this->setUser($this->teachers[0]);
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignfeedback_comments_enabled' => 1,
+            ]);
+
+        // Create an online text submission.
+        $this->add_submission($student, $assign);
+
+        $this->setUser($teacher);
 
         // Create formdata.
-        $data = new stdClass();
-        $data->assignfeedbackcomments_editor = array(
+        $grade = $assign->get_user_grade($student->id, true);
+        $data = (object) [
+            'assignfeedbackcomments_editor' => [
                 'text' => '<p>first comment for this test</p>',
-                'format' => 1
-            );
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
+                'format' => 1,
+            ]
+        ];
 
         // This is the first time that we are submitting feedback, so it is modified.
         $plugin = $assign->get_feedback_plugin_by_type('comments');
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
+
         // Save the feedback.
         $plugin->save($grade, $data);
+
         // Try again with the same data.
         $this->assertFalse($plugin->is_feedback_modified($grade, $data));
+
         // Change the data.
-        $data->assignfeedbackcomments_editor = array(
+        $data->assignfeedbackcomments_editor = [
                 'text' => '<p>Altered comment for this test</p>',
-                'format' => 1
-            );
+                'format' => 1,
+            ];
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
     }
 }
index 0182e80..db5d8d1 100644 (file)
@@ -33,7 +33,7 @@ use \assignfeedback_editpdf\comment;
 use \assignfeedback_editpdf\annotation;
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for assignfeedback_editpdf\comments_quick_list
@@ -41,31 +41,29 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  * @copyright  2013 Damyon Wiese
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
+class assignfeedback_editpdf_testcase extends advanced_testcase {
 
-    protected function setUp() {
+    // Use the generator helper.
+    use mod_assign_test_generator;
+
+    /**
+     * Ensure that GS is available.
+     */
+    protected function require_ghostscript() {
         // Skip this test if ghostscript is not supported.
         $result = pdf::test_gs_path(false);
         if ($result->status !== assignfeedback_editpdf\pdf::GSPATH_OK) {
             $this->markTestSkipped('Ghostscript not setup');
-            return;
         }
-        parent::setUp();
     }
 
-    protected function create_assign_and_submit_pdf() {
+    protected function add_file_submission($student, $assign) {
         global $CFG;
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
-                                               'assignsubmission_file_enabled' => 1,
-                                               'assignsubmission_file_maxfiles' => 1,
-                                               'assignfeedback_editpdf_enabled' => 1,
-                                               'assignsubmission_file_maxsizebytes' => 1000000));
 
-        $user = $this->students[0];
-        $this->setUser($user);
+        $this->setUser($student);
 
         // Create a file submission with the test pdf.
-        $submission = $assign->get_user_submission($user->id, true);
+        $submission = $assign->get_user_submission($student->id, true);
 
         $fs = get_file_storage();
         $pdfsubmission = (object) array(
@@ -77,27 +75,24 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
             'filename' => 'submission.pdf'
         );
         $sourcefile = $CFG->dirroot.'/mod/assign/feedback/editpdf/tests/fixtures/submission.pdf';
-        $fi = $fs->create_file_from_pathname($pdfsubmission, $sourcefile);
+        $fs->create_file_from_pathname($pdfsubmission, $sourcefile);
 
         $data = new stdClass();
         $plugin = $assign->get_submission_plugin_by_type('file');
         $plugin->save($submission, $data);
-
-        return $assign;
     }
 
     public function test_comments_quick_list() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
 
-        $comments = comments_quick_list::get_comments();
-
-        $this->assertEmpty($comments);
+        $this->assertEmpty(comments_quick_list::get_comments());
 
         $comment = comments_quick_list::add_comment('test', 45, 'red');
-
         $comments = comments_quick_list::get_comments();
-
         $this->assertEquals(count($comments), 1);
         $first = reset($comments);
         $this->assertEquals($comment, $first);
@@ -105,26 +100,36 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         $commentbyid = comments_quick_list::get_comment($comment->id);
         $this->assertEquals($comment, $commentbyid);
 
-        $result = comments_quick_list::remove_comment($comment->id);
-
-        $this->assertTrue($result);
+        $this->assertTrue(comments_quick_list::remove_comment($comment->id));
 
         $comments = comments_quick_list::get_comments();
         $this->assertEmpty($comments);
     }
 
     public function test_page_editor() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 1,
+                'assignfeedback_editpdf_enabled' => 1,
+                'assignsubmission_file_maxsizebytes' => 1000000,
+            ]);
+
+        // Add the standard submission.
+        $this->add_file_submission($student, $assign);
 
-        $assign = $this->create_assign_and_submit_pdf();
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
 
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
+        $grade = $assign->get_user_grade($student->id, true);
 
         $notempty = page_editor::has_annotations_or_comments($grade->id, false);
         $this->assertFalse($notempty);
 
         $comment = new comment();
-
         $comment->rawtext = 'Comment text';
         $comment->width = 100;
         $comment->x = 100;
@@ -132,7 +137,6 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         $comment->colour = 'red';
 
         $comment2 = new comment();
-
         $comment2->rawtext = 'Comment text 2';
         $comment2->width = 100;
         $comment2->x = 200;
@@ -142,7 +146,6 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         page_editor::set_comments($grade->id, 0, array($comment, $comment2));
 
         $annotation = new annotation();
-
         $annotation->path = '';
         $annotation->x = 100;
         $annotation->y = 100;
@@ -152,7 +155,6 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         $annotation->colour = 'red';
 
         $annotation2 = new annotation();
-
         $annotation2->path = '';
         $annotation2->x = 100;
         $annotation2->y = 100;
@@ -163,24 +165,19 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
 
         page_editor::set_annotations($grade->id, 0, array($annotation, $annotation2));
 
-        $notempty = page_editor::has_annotations_or_comments($grade->id, false);
         // Still empty because all edits are still drafts.
-        $this->assertFalse($notempty);
+        $this->assertFalse(page_editor::has_annotations_or_comments($grade->id, false));
 
         $comments = page_editor::get_comments($grade->id, 0, false);
-
         $this->assertEmpty($comments);
 
         $comments = page_editor::get_comments($grade->id, 0, true);
-
         $this->assertEquals(count($comments), 2);
 
         $annotations = page_editor::get_annotations($grade->id, 0, false);
-
         $this->assertEmpty($annotations);
 
         $annotations = page_editor::get_annotations($grade->id, 0, true);
-
         $this->assertEquals(count($annotations), 2);
 
         $comment = reset($comments);
@@ -190,32 +187,44 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         page_editor::remove_annotation($annotation->id);
 
         $comments = page_editor::get_comments($grade->id, 0, true);
-
         $this->assertEquals(count($comments), 1);
 
         $annotations = page_editor::get_annotations($grade->id, 0, true);
-
         $this->assertEquals(count($annotations), 1);
 
+        // Release the drafts.
         page_editor::release_drafts($grade->id);
 
         $notempty = page_editor::has_annotations_or_comments($grade->id, false);
-
         $this->assertTrue($notempty);
 
+        // Unrelease the drafts.
         page_editor::unrelease_drafts($grade->id);
 
         $notempty = page_editor::has_annotations_or_comments($grade->id, false);
-
         $this->assertFalse($notempty);
     }
 
     public function test_document_services() {
-
-        $assign = $this->create_assign_and_submit_pdf();
-        $this->setUser($this->teachers[0]);
-
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
+        $this->require_ghostscript();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 1,
+                'assignfeedback_editpdf_enabled' => 1,
+                'assignsubmission_file_maxsizebytes' => 1000000,
+            ]);
+
+        // Add the standard submission.
+        $this->add_file_submission($student, $assign);
+
+        $this->setUser($teacher);
+
+        $grade = $assign->get_user_grade($student->id, true);
 
         $contextid = $assign->get_context()->id;
         $component = 'assignfeedback_editpdf';
@@ -240,7 +249,7 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
         $this->assertEquals($combinedpdf->get_contenthash(), document_services::BLANK_PDF_HASH);
 
         // Generate page images and verify that the combined pdf has been replaced.
-        document_services::get_page_images_for_attempt($assign, $this->students[0]->id, -1);
+        document_services::get_page_images_for_attempt($assign, $student->id, -1);
         $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename);
         $this->assertNotEquals($combinedpdf->get_contenthash(), document_services::BLANK_PDF_HASH);
 
@@ -334,11 +343,23 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
      * and false when not modified.
      */
     public function test_is_feedback_modified() {
-        global $DB;
-        $assign = $this->create_assign_and_submit_pdf();
-        $this->setUser($this->teachers[0]);
-
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 1,
+                'assignfeedback_editpdf_enabled' => 1,
+                'assignsubmission_file_maxsizebytes' => 1000000,
+            ]);
+
+        // Add the standard submission.
+        $this->add_file_submission($student, $assign);
+
+        $this->setUser($teacher);
+        $grade = $assign->get_user_grade($student->id, true);
 
         $notempty = page_editor::has_annotations_or_comments($grade->id, false);
         $this->assertFalse($notempty);
@@ -369,7 +390,7 @@ class assignfeedback_editpdf_testcase extends mod_assign_base_testcase {
 
         $plugin = $assign->get_feedback_plugin_by_type('editpdf');
         $data = new stdClass();
-        $data->editpdf_source_userid = $this->students[0]->id;
+        $data->editpdf_source_userid = $student->id;
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
         $plugin->save($grade, $data);
 
index 6063dc1..6376b60 100644 (file)
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for assignfeedback_file
@@ -33,42 +33,32 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  * @copyright  2016 Adrian Greeve <adrian@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assignfeedback_file_testcase extends mod_assign_base_testcase {
+class assignfeedback_file_testcase extends advanced_testcase {
 
-    /**
-     * Create an assign object and submit an online text submission.
-     */
-    protected function create_assign_and_submit_text() {
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
-                                               'assignfeedback_comments_enabled' => 1));
-
-        $user = $this->students[0];
-        $this->setUser($user);
-
-        // Create an online text submission.
-        $submission = $assign->get_user_submission($user->id, true);
-
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-                'text' => '<p>This is some text.</p>',
-                'format' => 1,
-                'itemid' => file_get_unused_draft_itemid());
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
-
-        return $assign;
-    }
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test the is_feedback_modified() method for the file feedback.
      */
     public function test_is_feedback_modified() {
-        $assign = $this->create_assign_and_submit_text();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignfeedback_comments_enabled' => 1,
+            ]);
+
+        // Create an online text submission.
+        $this->add_submission($student, $assign);
 
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
 
         $fs = get_file_storage();
-        $context = context_user::instance($this->teachers[0]->id);
+        $context = context_user::instance($teacher->id);
         $draftitemid = file_get_unused_draft_itemid();
         file_prepare_draft_area($draftitemid, $context->id, 'assignfeedback_file', 'feedback_files', 1);
 
@@ -85,9 +75,9 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
+        $grade = $assign->get_user_grade($student->id, true);
 
         // This is the first time that we are submitting feedback, so it is modified.
         $plugin = $assign->get_feedback_plugin_by_type('file');
@@ -104,7 +94,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertFalse($plugin->is_feedback_modified($grade, $data));
 
@@ -118,7 +108,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
         $plugin->save($grade, $data);
@@ -135,7 +125,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
         $plugin->save($grade, $data);
@@ -150,7 +140,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
         $plugin->save($grade, $data);
@@ -166,7 +156,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertTrue($plugin->is_feedback_modified($grade, $data));
         $plugin->save($grade, $data);
@@ -182,7 +172,7 @@ class assignfeedback_file_testcase extends mod_assign_base_testcase {
 
         // Create formdata.
         $data = new stdClass();
-        $data->{'files_' . $this->students[0]->id . '_filemanager'} = $draftitemid;
+        $data->{'files_' . $student->id . '_filemanager'} = $draftitemid;
 
         $this->assertFalse($plugin->is_feedback_modified($grade, $data));
     }
index eacc25c..2ec414a 100644 (file)
@@ -28,7 +28,8 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 require_once($CFG->dirroot . '/mod/assign/lib.php');
 require_once($CFG->dirroot . '/mod/assign/locallib.php');
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
+require_once($CFG->dirroot . '/comment/lib.php');
 
 /**
  * Events tests class.
@@ -38,18 +39,24 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assignsubmission_comments_events_testcase extends mod_assign_base_testcase {
+class assignsubmission_comments_events_testcase extends advanced_testcase {
+
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test comment_created event.
      */
     public function test_comment_created() {
-        global $CFG;
-        require_once($CFG->dirroot . '/comment/lib.php');
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($teacher);
+        $submission = $assign->get_user_submission($student->id, true);
 
         $context = $assign->get_context();
         $options = new stdClass();
@@ -69,6 +76,7 @@ class assignsubmission_comments_events_testcase extends mod_assign_base_testcase
         $events = $sink->get_events();
         $this->assertCount(1, $events);
         $event = reset($events);
+        $sink->close();
 
         // Checking that the event contains the expected values.
         $this->assertInstanceOf('\assignsubmission_comments\event\comment_created', $event);
@@ -82,12 +90,15 @@ class assignsubmission_comments_events_testcase extends mod_assign_base_testcase
      * Test comment_deleted event.
      */
     public function test_comment_deleted() {
-        global $CFG;
-        require_once($CFG->dirroot . '/comment/lib.php');
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($teacher);
+        $submission = $assign->get_user_submission($student->id, true);
 
         $context = $assign->get_context();
         $options = new stdClass();
index f8f4eac..45e19b3 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 class assignsubmission_file_events_testcase extends advanced_testcase {
 
-    /** @var stdClass $user A user to submit an assignment. */
-    protected $user;
-
-    /** @var stdClass $course New course created to hold the assignment activity. */
-    protected $course;
-
-    /** @var stdClass $cm A context module object. */
-    protected $cm;
-
-    /** @var stdClass $context Context of the assignment activity. */
-    protected $context;
-
-    /** @var stdClass $assign The assignment object. */
-    protected $assign;
-
-    /** @var stdClass $files Files that are being submitted for the assignment. */
-    protected $files;
-
-    /** @var stdClass $submission Submission information. */
-    protected $submission;
-
-    /** @var stdClass $fi File information - First file*/
-    protected $fi;
-
-    /** @var stdClass $fi2 File information - Second file*/
-    protected $fi2;
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
-     * Setup all the various parts of an assignment activity including creating a file submission.
+     * Test that the assessable_uploaded event is fired when a file submission has been made.
      */
-    protected function setUp() {
-        $this->user = $this->getDataGenerator()->create_user();
-        $this->course = $this->getDataGenerator()->create_course();
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $params['course'] = $this->course->id;
-        $instance = $generator->create_instance($params);
-        $this->cm = get_coursemodule_from_instance('assign', $instance->id);
-        $this->context = context_module::instance($this->cm->id);
-        $this->assign = new testable_assign($this->context, $this->cm, $this->course);
-
-        $this->setUser($this->user->id);
-        $this->submission = $this->assign->get_user_submission($this->user->id, true);
+    public function test_assessable_uploaded() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+        $cm = $assign->get_course_module();
+
+        $this->setUser($student->id);
+        $submission = $assign->get_user_submission($student->id, true);
 
         $fs = get_file_storage();
         $dummy = (object) array(
-            'contextid' => $this->context->id,
+            'contextid' => $context->id,
             'component' => 'assignsubmission_file',
             'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
-            'itemid' => $this->submission->id,
+            'itemid' => $submission->id,
             'filepath' => '/',
             'filename' => 'myassignmnent.pdf'
         );
-        $this->fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
         $dummy = (object) array(
-            'contextid' => $this->context->id,
+            'contextid' => $context->id,
             'component' => 'assignsubmission_file',
             'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
-            'itemid' => $this->submission->id,
+            'itemid' => $submission->id,
             'filepath' => '/',
             'filename' => 'myassignmnent.png'
         );
-        $this->fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
-        $this->files = $fs->get_area_files($this->context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
-            $this->submission->id, 'id', false);
-
-    }
-
-    /**
-     * Test that the assessable_uploaded event is fired when a file submission has been made.
-     */
-    public function test_assessable_uploaded() {
-        $this->resetAfterTest();
+        $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
+            $submission->id, 'id', false);
 
         $data = new stdClass();
-        $plugin = $this->assign->get_submission_plugin_by_type('file');
+        $plugin = $assign->get_submission_plugin_by_type('file');
         $sink = $this->redirectEvents();
-        $plugin->save($this->submission, $data);
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
         $this->assertCount(2, $events);
         $event = reset($events);
         $this->assertInstanceOf('\assignsubmission_file\event\assessable_uploaded', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->submission->id, $event->objectid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($submission->id, $event->objectid);
         $this->assertCount(2, $event->other['pathnamehashes']);
-        $this->assertEquals($this->fi->get_pathnamehash(), $event->other['pathnamehashes'][0]);
-        $this->assertEquals($this->fi2->get_pathnamehash(), $event->other['pathnamehashes'][1]);
+        $this->assertEquals($fi->get_pathnamehash(), $event->other['pathnamehashes'][0]);
+        $this->assertEquals($fi2->get_pathnamehash(), $event->other['pathnamehashes'][1]);
         $expected = new stdClass();
         $expected->modulename = 'assign';
-        $expected->cmid = $this->cm->id;
-        $expected->itemid = $this->submission->id;
-        $expected->courseid = $this->course->id;
-        $expected->userid = $this->user->id;
-        $expected->file = $this->files;
-        $expected->files = $this->files;
-        $expected->pathnamehashes = array($this->fi->get_pathnamehash(), $this->fi2->get_pathnamehash());
+        $expected->cmid = $cm->id;
+        $expected->itemid = $submission->id;
+        $expected->courseid = $course->id;
+        $expected->userid = $student->id;
+        $expected->file = $files;
+        $expected->files = $files;
+        $expected->pathnamehashes = array($fi->get_pathnamehash(), $fi2->get_pathnamehash());
         $this->assertEventLegacyData($expected, $event);
         $this->assertEventContextNotUsed($event);
     }
@@ -135,22 +102,52 @@ class assignsubmission_file_events_testcase extends advanced_testcase {
     public function test_submission_created() {
         $this->resetAfterTest();
 
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+
+        $this->setUser($student->id);
+        $submission = $assign->get_user_submission($student->id, true);
+
+        $fs = get_file_storage();
+        $dummy = (object) array(
+            'contextid' => $context->id,
+            'component' => 'assignsubmission_file',
+            'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
+            'itemid' => $submission->id,
+            'filepath' => '/',
+            'filename' => 'myassignmnent.pdf'
+        );
+        $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $dummy = (object) array(
+            'contextid' => $context->id,
+            'component' => 'assignsubmission_file',
+            'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
+            'itemid' => $submission->id,
+            'filepath' => '/',
+            'filename' => 'myassignmnent.png'
+        );
+        $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
+            $submission->id, 'id', false);
+
         $data = new stdClass();
-        $plugin = $this->assign->get_submission_plugin_by_type('file');
+        $plugin = $assign->get_submission_plugin_by_type('file');
         $sink = $this->redirectEvents();
-        $plugin->save($this->submission, $data);
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
         $this->assertCount(2, $events);
         // We want to test the last event fired.
         $event = $events[1];
         $this->assertInstanceOf('\assignsubmission_file\event\submission_created', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-        $this->assertEquals($this->submission->id, $event->other['submissionid']);
-        $this->assertEquals($this->submission->attemptnumber, $event->other['submissionattempt']);
-        $this->assertEquals($this->submission->status, $event->other['submissionstatus']);
-        $this->assertEquals($this->submission->userid, $event->relateduserid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($course->id, $event->courseid);
+        $this->assertEquals($submission->id, $event->other['submissionid']);
+        $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']);
+        $this->assertEquals($submission->status, $event->other['submissionstatus']);
+        $this->assertEquals($submission->userid, $event->relateduserid);
     }
 
     /**
@@ -159,25 +156,55 @@ class assignsubmission_file_events_testcase extends advanced_testcase {
     public function test_submission_updated() {
         $this->resetAfterTest();
 
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+
+        $this->setUser($student->id);
+        $submission = $assign->get_user_submission($student->id, true);
+
+        $fs = get_file_storage();
+        $dummy = (object) array(
+            'contextid' => $context->id,
+            'component' => 'assignsubmission_file',
+            'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
+            'itemid' => $submission->id,
+            'filepath' => '/',
+            'filename' => 'myassignmnent.pdf'
+        );
+        $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $dummy = (object) array(
+            'contextid' => $context->id,
+            'component' => 'assignsubmission_file',
+            'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
+            'itemid' => $submission->id,
+            'filepath' => '/',
+            'filename' => 'myassignmnent.png'
+        );
+        $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
+        $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
+            $submission->id, 'id', false);
+
         $data = new stdClass();
-        $plugin = $this->assign->get_submission_plugin_by_type('file');
+        $plugin = $assign->get_submission_plugin_by_type('file');
         $sink = $this->redirectEvents();
         // Create a submission.
-        $plugin->save($this->submission, $data);
+        $plugin->save($submission, $data);
         // Update a submission.
-        $plugin->save($this->submission, $data);
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
         $this->assertCount(4, $events);
         // We want to test the last event fired.
         $event = $events[3];
         $this->assertInstanceOf('\assignsubmission_file\event\submission_updated', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-        $this->assertEquals($this->submission->id, $event->other['submissionid']);
-        $this->assertEquals($this->submission->attemptnumber, $event->other['submissionattempt']);
-        $this->assertEquals($this->submission->status, $event->other['submissionstatus']);
-        $this->assertEquals($this->submission->userid, $event->relateduserid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($course->id, $event->courseid);
+        $this->assertEquals($submission->id, $event->other['submissionid']);
+        $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']);
+        $this->assertEquals($submission->status, $event->other['submissionstatus']);
+        $this->assertEquals($submission->userid, $event->relateduserid);
     }
 
 }
index 2291d62..b033946 100644 (file)
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for mod/assign/submission/file/locallib.php
@@ -35,40 +35,8 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  */
 class assignsubmission_file_locallib_testcase extends advanced_testcase {
 
-    /** @var stdClass $user A user to submit an assignment. */
-    protected $user;
-
-    /** @var stdClass $course New course created to hold the assignment activity. */
-    protected $course;
-
-    /** @var stdClass $cm A context module object. */
-    protected $cm;
-
-    /** @var stdClass $context Context of the assignment activity. */
-    protected $context;
-
-    /** @var stdClass $assign The assignment object. */
-    protected $assign;
-
-    /**
-     * Setup all the various parts of an assignment activity including creating an onlinetext submission.
-     */
-    protected function setUp() {
-        $this->user = $this->getDataGenerator()->create_user();
-        $this->course = $this->getDataGenerator()->create_course();
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $params = [
-            'course' => $this->course->id,
-            'assignsubmission_file_enabled' => 1,
-            'assignsubmission_file_maxfiles' => 12,
-            'assignsubmission_file_maxsizebytes' => 10,
-        ];
-        $instance = $generator->create_instance($params);
-        $this->cm = get_coursemodule_from_instance('assign', $instance->id);
-        $this->context = context_module::instance($this->cm->id);
-        $this->assign = new testable_assign($this->context, $this->cm, $this->course);
-        $this->setUser($this->user->id);
-    }
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test submission_is_empty
@@ -80,12 +48,22 @@ class assignsubmission_file_locallib_testcase extends advanced_testcase {
     public function test_submission_is_empty($data, $expected) {
         $this->resetAfterTest();
 
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 12,
+                'assignsubmission_file_maxsizebytes' => 10,
+            ]);
+
+        $this->setUser($student->id);
+
         $itemid = file_get_unused_draft_itemid();
         $submission = (object)['files_filemanager' => $itemid];
-        $plugin = $this->assign->get_submission_plugin_by_type('file');
+        $plugin = $assign->get_submission_plugin_by_type('file');
 
         if ($data) {
-            $data += ['contextid' => context_user::instance($this->user->id)->id, 'itemid' => $itemid];
+            $data += ['contextid' => context_user::instance($student->id)->id, 'itemid' => $itemid];
             $fs = get_file_storage();
             $fs->create_file_from_string((object)$data, 'Content of ' . $data['filename']);
         }
@@ -104,16 +82,26 @@ class assignsubmission_file_locallib_testcase extends advanced_testcase {
     public function test_new_submission_empty($data, $expected) {
         $this->resetAfterTest();
 
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 12,
+                'assignsubmission_file_maxsizebytes' => 10,
+            ]);
+
+        $this->setUser($student);
+
         $itemid = file_get_unused_draft_itemid();
-        $submission = (object)['files_filemanager' => $itemid];
+        $submission = (object) ['files_filemanager' => $itemid];
 
         if ($data) {
-            $data += ['contextid' => context_user::instance($this->user->id)->id, 'itemid' => $itemid];
+            $data += ['contextid' => context_user::instance($student->id)->id, 'itemid' => $itemid];
             $fs = get_file_storage();
             $fs->create_file_from_string((object)$data, 'Content of ' . $data['filename']);
         }
 
-        $result = $this->assign->new_submission_empty($submission);
+        $result = $assign->new_submission_empty($submission);
         $this->assertTrue($result === $expected);
     }
 
index 56cf1ef..7c5c07a 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 class assignsubmission_onlinetext_events_testcase extends advanced_testcase {
 
-    /** @var stdClass $user A user to submit an assignment. */
-    protected $user;
-
-    /** @var stdClass $course New course created to hold the assignment activity. */
-    protected $course;
-
-    /** @var stdClass $cm A context module object. */
-    protected $cm;
-
-    /** @var stdClass $context Context of the assignment activity. */
-    protected $context;
-
-    /** @var stdClass $assign The assignment object. */
-    protected $assign;
-
-    /** @var stdClass $submission Submission information. */
-    protected $submission;
-
-    /** @var stdClass $data General data for the assignment submission. */
-    protected $data;
-
-    /**
-     * Setup all the various parts of an assignment activity including creating an onlinetext submission.
-     */
-    protected function setUp() {
-        $this->user = $this->getDataGenerator()->create_user();
-        $this->course = $this->getDataGenerator()->create_course();
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $params['course'] = $this->course->id;
-        $instance = $generator->create_instance($params);
-        $this->cm = get_coursemodule_from_instance('assign', $instance->id);
-        $this->context = context_module::instance($this->cm->id);
-        $this->assign = new testable_assign($this->context, $this->cm, $this->course);
-
-        $this->setUser($this->user->id);
-        $this->submission = $this->assign->get_user_submission($this->user->id, true);
-        $this->data = new stdClass();
-        $this->data->onlinetext_editor = array(
-            'itemid' => file_get_unused_draft_itemid(),
-            'text' => 'Submission text',
-            'format' => FORMAT_PLAIN
-        );
-    }
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test that the assessable_uploaded event is fired when an online text submission is saved.
@@ -79,25 +38,42 @@ class assignsubmission_onlinetext_events_testcase extends advanced_testcase {
     public function test_assessable_uploaded() {
         $this->resetAfterTest();
 
-        $plugin = $this->assign->get_submission_plugin_by_type('onlinetext');
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+        $cm = $assign->get_course_module();
+
+        $this->setUser($student->id);
+
+        $submission = $assign->get_user_submission($student->id, true);
+        $data = (object) [
+            'onlinetext_editor' => [
+                'itemid' => file_get_unused_draft_itemid(),
+                'text' => 'Submission text',
+                'format' => FORMAT_PLAIN,
+            ],
+        ];
+
         $sink = $this->redirectEvents();
-        $plugin->save($this->submission, $this->data);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
         $this->assertCount(2, $events);
         $event = reset($events);
         $this->assertInstanceOf('\assignsubmission_onlinetext\event\assessable_uploaded', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->submission->id, $event->objectid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($submission->id, $event->objectid);
         $this->assertEquals(array(), $event->other['pathnamehashes']);
         $this->assertEquals(FORMAT_PLAIN, $event->other['format']);
         $this->assertEquals('Submission text', $event->other['content']);
         $expected = new stdClass();
         $expected->modulename = 'assign';
-        $expected->cmid = $this->cm->id;
-        $expected->itemid = $this->submission->id;
-        $expected->courseid = $this->course->id;
-        $expected->userid = $this->user->id;
+        $expected->cmid = $cm->id;
+        $expected->itemid = $submission->id;
+        $expected->courseid = $course->id;
+        $expected->userid = $student->id;
         $expected->content = 'Submission text';
         $this->assertEventLegacyData($expected, $event);
         $this->assertEventContextNotUsed($event);
@@ -109,20 +85,36 @@ class assignsubmission_onlinetext_events_testcase extends advanced_testcase {
     public function test_submission_created() {
         $this->resetAfterTest();
 
-        $plugin = $this->assign->get_submission_plugin_by_type('onlinetext');
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+
+        $this->setUser($student->id);
+
+        $submission = $assign->get_user_submission($student->id, true);
+        $data = (object) [
+            'onlinetext_editor' => [
+                'itemid' => file_get_unused_draft_itemid(),
+                'text' => 'Submission text',
+                'format' => FORMAT_PLAIN,
+            ],
+        ];
+
         $sink = $this->redirectEvents();
-        $plugin->save($this->submission, $this->data);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
         $this->assertCount(2, $events);
         $event = $events[1];
         $this->assertInstanceOf('\assignsubmission_onlinetext\event\submission_created', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-        $this->assertEquals($this->submission->id, $event->other['submissionid']);
-        $this->assertEquals($this->submission->attemptnumber, $event->other['submissionattempt']);
-        $this->assertEquals($this->submission->status, $event->other['submissionstatus']);
-        $this->assertEquals($this->submission->userid, $event->relateduserid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($course->id, $event->courseid);
+        $this->assertEquals($submission->id, $event->other['submissionid']);
+        $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']);
+        $this->assertEquals($submission->status, $event->other['submissionstatus']);
+        $this->assertEquals($submission->userid, $event->relateduserid);
     }
 
     /**
@@ -132,22 +124,39 @@ class assignsubmission_onlinetext_events_testcase extends advanced_testcase {
     public function test_submission_updated() {
         $this->resetAfterTest();
 
-        $plugin = $this->assign->get_submission_plugin_by_type('onlinetext');
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $context = $assign->get_context();
+
+        $this->setUser($student->id);
+
+        $submission = $assign->get_user_submission($student->id, true);
+        $data = (object) [
+            'onlinetext_editor' => [
+                'itemid' => file_get_unused_draft_itemid(),
+                'text' => 'Submission text',
+                'format' => FORMAT_PLAIN,
+            ],
+        ];
+
         $sink = $this->redirectEvents();
-        // Create a submission.
-        $plugin->save($this->submission, $this->data);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $plugin->save($submission, $data);
+        $sink->clear();
+
         // Update a submission.
-        $plugin->save($this->submission, $this->data);
+        $plugin->save($submission, $data);
         $events = $sink->get_events();
 
-        $this->assertCount(4, $events);
-        $event = $events[3];
+        $this->assertCount(2, $events);
+        $event = $events[1];
         $this->assertInstanceOf('\assignsubmission_onlinetext\event\submission_updated', $event);
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-        $this->assertEquals($this->submission->id, $event->other['submissionid']);
-        $this->assertEquals($this->submission->attemptnumber, $event->other['submissionattempt']);
-        $this->assertEquals($this->submission->status, $event->other['submissionstatus']);
-        $this->assertEquals($this->submission->userid, $event->relateduserid);
+        $this->assertEquals($context->id, $event->contextid);
+        $this->assertEquals($course->id, $event->courseid);
+        $this->assertEquals($submission->id, $event->other['submissionid']);
+        $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']);
+        $this->assertEquals($submission->status, $event->other['submissionstatus']);
+        $this->assertEquals($submission->userid, $event->relateduserid);
     }
 }
index c7595c4..2448c39 100644 (file)
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for mod/assign/submission/onlinetext/locallib.php
@@ -35,35 +35,8 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  */
 class assignsubmission_onlinetext_locallib_testcase extends advanced_testcase {
 
-    /** @var stdClass $user A user to submit an assignment. */
-    protected $user;
-
-    /** @var stdClass $course New course created to hold the assignment activity. */
-    protected $course;
-
-    /** @var stdClass $cm A context module object. */
-    protected $cm;
-
-    /** @var stdClass $context Context of the assignment activity. */
-    protected $context;
-
-    /** @var stdClass $assign The assignment object. */
-    protected $assign;
-
-    /**
-     * Setup all the various parts of an assignment activity including creating an onlinetext submission.
-     */
-    protected function setUp() {
-        $this->user = $this->getDataGenerator()->create_user();
-        $this->course = $this->getDataGenerator()->create_course();
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $params = ['course' => $this->course->id, 'assignsubmission_onlinetext_enabled' => 1];
-        $instance = $generator->create_instance($params);
-        $this->cm = get_coursemodule_from_instance('assign', $instance->id);
-        $this->context = context_module::instance($this->cm->id);
-        $this->assign = new testable_assign($this->context, $this->cm, $this->course);
-        $this->setUser($this->user->id);
-    }
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Test submission_is_empty
@@ -75,11 +48,20 @@ class assignsubmission_onlinetext_locallib_testcase extends advanced_testcase {
     public function test_submission_is_empty($submissiontext, $expected) {
         $this->resetAfterTest();
 
-        $plugin = $this->assign->get_submission_plugin_by_type('onlinetext');
-        $data = new stdClass();
-        $data->onlinetext_editor = ['text' => $submissiontext];
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => true,
+            ]);
+
+        $this->setUser($student->id);
 
-        $result = $plugin->submission_is_empty($data);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $result = $plugin->submission_is_empty((object) [
+                'onlinetext_editor' => [
+                    'text' => $submissiontext,
+                ],
+            ]);
         $this->assertTrue($result === $expected);
     }
 
@@ -92,10 +74,21 @@ class assignsubmission_onlinetext_locallib_testcase extends advanced_testcase {
      */
     public function test_new_submission_empty($submissiontext, $expected) {
         $this->resetAfterTest();
-        $data = new stdClass();
-        $data->onlinetext_editor = ['text' => $submissiontext];
 
-        $result = $this->assign->new_submission_empty($data);
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => true,
+            ]);
+
+        $this->setUser($student->id);
+
+        $result = $assign->new_submission_empty((object) [
+                'onlinetext_editor' => [
+                    'text' => $submissiontext,
+                ],
+            ]);
+
         $this->assertTrue($result === $expected);
     }
 
index ab2a056..d30f989 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 require_once($CFG->dirroot . '/mod/assign/locallib.php');
 require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
+require_once(__DIR__ . '/fixtures/testable_assign.php');
 
 /**
  * Unit tests for (some of) mod/assign/locallib.php.
@@ -211,7 +212,7 @@ class mod_assign_base_testcase extends advanced_testcase {
         $instance = $generator->create_instance($params);
         $cm = get_coursemodule_from_instance('assign', $instance->id);
         $context = context_module::instance($cm->id);
-        return new testable_assign($context, $cm, $this->course);
+        return new mod_assign_testable_assign($context, $cm, $this->course);
     }
 
     public function test_create_instance() {
@@ -220,150 +221,4 @@ class mod_assign_base_testcase extends advanced_testcase {
 
 }
 
-/**
- * Test subclass that makes all the protected methods we want to test public.
- */
-class testable_assign extends assign {
-
-    public function testable_show_intro() {
-        return parent::show_intro();
-    }
-
-    public function testable_delete_grades() {
-        return parent::delete_grades();
-    }
-
-    public function testable_apply_grade_to_user($formdata, $userid, $attemptnumber) {
-        return parent::apply_grade_to_user($formdata, $userid, $attemptnumber);
-    }
-
-    public function testable_format_submission_for_log(stdClass $submission) {
-        return parent::format_submission_for_log($submission);
-    }
-
-    public function testable_get_grading_userid_list() {
-        return parent::get_grading_userid_list();
-    }
-
-    public function testable_is_graded($userid) {
-        return parent::is_graded($userid);
-    }
-
-    public function testable_update_submission(stdClass $submission, $userid, $updatetime, $teamsubmission) {
-        return parent::update_submission($submission, $userid, $updatetime, $teamsubmission);
-    }
-
-    public function testable_process_add_attempt($userid = 0) {
-        return parent::process_add_attempt($userid);
-    }
-
-    public function testable_process_save_quick_grades($postdata) {
-        // Ugly hack to get something into the method.
-        global $_POST;
-        $_POST = $postdata;
-        return parent::process_save_quick_grades();
-    }
-
-    public function testable_process_set_batch_marking_allocation($selectedusers, $markerid) {
-        global $CFG;
-        require_once($CFG->dirroot . '/mod/assign/batchsetallocatedmarkerform.php');
-
-        // Simulate the form submission.
-        $data = array();
-        $data['id'] = $this->get_course_module()->id;
-        $data['selectedusers'] = $selectedusers;
-        $data['allocatedmarker'] = $markerid;
-        $data['action'] = 'setbatchmarkingallocation';
-        mod_assign_batch_set_allocatedmarker_form::mock_submit($data);
-
-        return parent::process_set_batch_marking_allocation();
-    }
-
-    public function testable_process_set_batch_marking_workflow_state($selectedusers, $state) {
-        global $CFG;
-        require_once($CFG->dirroot . '/mod/assign/batchsetmarkingworkflowstateform.php');
-
-        // Simulate the form submission.
-        $data = array();
-        $data['id'] = $this->get_course_module()->id;
-        $data['selectedusers'] = $selectedusers;
-        $data['markingworkflowstate'] = $state;
-        $data['action'] = 'setbatchmarkingworkflowstate';
-        mod_assign_batch_set_marking_workflow_state_form::mock_submit($data);
-
-        return parent::process_set_batch_marking_workflow_state();
-    }
-
-    public function testable_submissions_open($userid = 0) {
-        return parent::submissions_open($userid);
-    }
-
-    public function testable_save_user_extension($userid, $extensionduedate) {
-        return parent::save_user_extension($userid, $extensionduedate);
-    }
-
-    public function testable_get_graders($userid) {
-        // Changed method from protected to public.
-        return parent::get_graders($userid);
-    }
-
-    public function testable_get_notifiable_users($userid) {
-        return parent::get_notifiable_users($userid);
-    }
-
-    public function testable_view_batch_set_workflow_state($selectedusers) {
-        global $PAGE;
-        $PAGE->set_url('/mod/assign/view.php');
-        $mform = $this->testable_grading_batch_operations_form('setmarkingworkflowstate', $selectedusers);
-        return parent::view_batch_set_workflow_state($mform);
-    }
-
-    public function testable_view_batch_markingallocation($selectedusers) {
-        global $PAGE;
-        $PAGE->set_url('/mod/assign/view.php');
-        $mform = $this->testable_grading_batch_operations_form('setmarkingallocation', $selectedusers);
-        return parent::view_batch_markingallocation($mform);
-    }
-
-    public function testable_grading_batch_operations_form($operation, $selectedusers) {
-        global $CFG;
-
-        require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
-
-        // Mock submit the grading operations form.
-        $data = array();
-        $data['id'] = $this->get_course_module()->id;
-        $data['selectedusers'] = $selectedusers;
-        $data['returnaction'] = 'grading';
-        $data['operation'] = $operation;
-        mod_assign_grading_batch_operations_form::mock_submit($data);
-
-        // Set required variables in the form.
-        $formparams = array();
-        $formparams['submissiondrafts'] = 1;
-        $formparams['duedate'] = 1;
-        $formparams['attemptreopenmethod'] = ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL;
-        $formparams['feedbackplugins'] = array();
-        $formparams['markingworkflow'] = 1;
-        $formparams['markingallocation'] = 1;
-        $formparams['cm'] = $this->get_course_module()->id;
-        $formparams['context'] = $this->get_context();
-        $mform = new mod_assign_grading_batch_operations_form(null, $formparams);
-
-        return $mform;
-    }
-
-    public function testable_update_activity_completion_records($teamsubmission,
-                                                          $requireallteammemberssubmit,
-                                                          $submission,
-                                                          $userid,
-                                                          $complete,
-                                                          $completion) {
-        return parent::update_activity_completion_records($teamsubmission,
-                                                          $requireallteammemberssubmit,
-                                                          $submission,
-                                                          $userid,
-                                                          $complete,
-                                                          $completion);
-    }
-}
+class_alias('mod_assign_testable_assign', 'testable_assign');
index 5d14028..8dfd768 100644 (file)
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 require_once($CFG->dirroot . '/mod/assign/tests/fixtures/event_mod_assign_fixtures.php');
 require_once($CFG->dirroot . '/mod/assign/locallib.php');
 
@@ -36,20 +36,25 @@ require_once($CFG->dirroot . '/mod/assign/locallib.php');
  * @copyright 2014 Adrian Greeve <adrian@moodle.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assign_events_testcase extends mod_assign_base_testcase {
+class assign_events_testcase extends advanced_testcase {
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     /**
      * Basic tests for the submission_created() abstract class.
      */
     public function test_base_event() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $instance = $generator->create_instance(array('course' => $course->id));
         $modcontext = context_module::instance($instance->cmid);
 
         $data = array(
             'context' => $modcontext,
         );
-        /** @var \mod_assign_unittests\event\nothing_happened $event */
+
         $event = \mod_assign_unittests\event\nothing_happened::create($data);
         $assign = $event->get_assign();
         $this->assertDebuggingCalled();
@@ -66,14 +71,17 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * Basic tests for the submission_created() abstract class.
      */
     public function test_submission_created() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $instance = $generator->create_instance(array('course' => $course->id));
         $modcontext = context_module::instance($instance->cmid);
 
         // Standard Event parameters.
         $params = array(
             'context' => $modcontext,
-            'courseid' => $this->course->id
+            'courseid' => $course->id
         );
 
         $eventinfo = $params;
@@ -91,7 +99,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $sink->close();
 
         $this->assertEquals($modcontext->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
+        $this->assertEquals($course->id, $event->courseid);
 
         // Check that an error occurs when teamsubmission is not set.
         try {
@@ -123,14 +131,17 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * Basic tests for the submission_updated() abstract class.
      */
     public function test_submission_updated() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $instance = $generator->create_instance(array('course' => $course->id));
         $modcontext = context_module::instance($instance->cmid);
 
         // Standard Event parameters.
         $params = array(
             'context' => $modcontext,
-            'courseid' => $this->course->id
+            'courseid' => $course->id
         );
 
         $eventinfo = $params;
@@ -148,7 +159,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $sink->close();
 
         $this->assertEquals($modcontext->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
+        $this->assertEquals($course->id, $event->courseid);
 
         // Check that an error occurs when teamsubmission is not set.
         try {
@@ -177,15 +188,25 @@ class assign_events_testcase extends mod_assign_base_testcase {
     }
 
     public function test_extension_granted() {
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $tomorrow = time() + 24*60*60;
-        $yesterday = time() - 24*60*60;
+        $this->setUser($teacher);
 
-        $assign = $this->create_instance(array('duedate' => $yesterday, 'cutoffdate' => $yesterday));
+        $now = time();
+        $tomorrow = $now + DAYSECS;
+        $yesterday = $now - DAYSECS;
+
+        $assign = $this->create_instance($course, [
+            'duedate' => $yesterday,
+            'cutoffdate' => $yesterday,
+        ]);
         $sink = $this->redirectEvents();
 
-        $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
+        $assign->testable_save_user_extension($student->id, $tomorrow);
 
         $events = $sink->get_events();
         $this->assertCount(1, $events);
@@ -193,13 +214,14 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\extension_granted', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
+
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'grant extension',
             'view.php?id=' . $assign->get_course_module()->id,
-            $this->students[0]->id,
+            $student->id,
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -207,13 +229,19 @@ class assign_events_testcase extends mod_assign_base_testcase {
     }
 
     public function test_submission_locked() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
 
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
         $sink = $this->redirectEvents();
 
-        $assign->lock_submission($this->students[0]->id);
+        $assign->lock_submission($student->id);
 
         $events = $sink->get_events();
         $this->assertCount(1, $events);
@@ -221,28 +249,30 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_locked', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'lock submission',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('locksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
+            get_string('locksubmissionforstudent', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student))),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     public function test_identities_revealed() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
 
-        $assign = $this->create_instance(array('blindmarking'=>1));
+        $assign = $this->create_instance($course, ['blindmarking' => 1]);
         $sink = $this->redirectEvents();
 
         $assign->reveal_identities();
@@ -263,9 +293,6 @@ class assign_events_testcase extends mod_assign_base_testcase {
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     /**
@@ -273,10 +300,14 @@ class assign_events_testcase extends mod_assign_base_testcase {
      */
     public function test_submission_status_viewed() {
         global $PAGE;
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
 
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the feedback.
         $PAGE->set_url('/a_url');
@@ -304,16 +335,21 @@ class assign_events_testcase extends mod_assign_base_testcase {
     }
 
     public function test_submission_status_updated() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $assign->testable_update_submission($submission, $student->id, true, false);
 
         $sink = $this->redirectEvents();
-        $assign->revert_to_draft($this->students[0]->id);
+        $assign->revert_to_draft($student->id);
 
         $events = $sink->get_events();
         $this->assertCount(2, $events);
@@ -321,32 +357,35 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_status_updated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($submission->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $this->assertEquals(ASSIGN_SUBMISSION_STATUS_DRAFT, $event->other['newstatus']);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'revert submission to draft',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('reverttodraftforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
+            get_string('reverttodraftforstudent', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student))),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     public function test_marker_updated() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
 
         $sink = $this->redirectEvents();
-        $assign->testable_process_set_batch_marking_allocation($this->students[0]->id, $this->teachers[0]->id);
+        $assign->testable_process_set_batch_marking_allocation($student->id, $teacher->id);
 
         $events = $sink->get_events();
         $this->assertCount(1, $events);
@@ -354,34 +393,37 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\marker_updated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
-        $this->assertEquals($this->teachers[0]->id, $event->other['markerid']);
+        $this->assertEquals($student->id, $event->relateduserid);
+        $this->assertEquals($teacher->id, $event->userid);
+        $this->assertEquals($teacher->id, $event->other['markerid']);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'set marking allocation',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkerallocationforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'marker' => fullname($this->teachers[0]))),
+            get_string('setmarkerallocationforlog', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student), 'marker' => fullname($teacher))),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     public function test_workflow_state_updated() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
 
         // Test process_set_batch_marking_workflow_state.
         $sink = $this->redirectEvents();
-        $assign->testable_process_set_batch_marking_workflow_state($this->students[0]->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
+        $assign->testable_process_set_batch_marking_workflow_state($student->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
 
         $events = $sink->get_events();
         $this->assertCount(1, $events);
@@ -389,16 +431,16 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
+        $this->assertEquals($student->id, $event->relateduserid);
+        $this->assertEquals($teacher->id, $event->userid);
         $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW, $event->other['newstate']);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'set marking workflow state',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
+            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -409,7 +451,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $data = new stdClass();
         $data->grade = '50.0';
         $data->workflowstate = 'readyforrelease';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $assign->testable_apply_grade_to_user($data, $student->id, 0);
 
         $events = $sink->get_events();
         $this->assertCount(4, $events);
@@ -417,16 +459,16 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
+        $this->assertEquals($student->id, $event->relateduserid);
+        $this->assertEquals($teacher->id, $event->userid);
         $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE, $event->other['newstate']);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'set marking workflow state',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE)),
+            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE)),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -436,10 +478,10 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $sink = $this->redirectEvents();
 
         $data = array(
-            'grademodified_' . $this->students[0]->id => time(),
-            'gradeattempt_' . $this->students[0]->id => '',
-            'quickgrade_' . $this->students[0]->id => '60.0',
-            'quickgrade_' . $this->students[0]->id . '_workflowstate' => 'inmarking'
+            'grademodified_' . $student->id => time(),
+            'gradeattempt_' . $student->id => '',
+            'quickgrade_' . $student->id => '60.0',
+            'quickgrade_' . $student->id . '_workflowstate' => 'inmarking'
         );
         $assign->testable_process_save_quick_grades($data);
 
@@ -449,33 +491,35 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
+        $this->assertEquals($student->id, $event->relateduserid);
+        $this->assertEquals($teacher->id, $event->userid);
         $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INMARKING, $event->other['newstate']);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'set marking workflow state',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INMARKING)),
+            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INMARKING)),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     public function test_submission_duplicated() {
-        $this->setUser($this->students[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
-        $submission1 = $assign->get_user_submission($this->students[0]->id, true, 0);
-        $submission2 = $assign->get_user_submission($this->students[0]->id, true, 1);
+        $this->setUser($student);
+
+        $assign = $this->create_instance($course);
+        $submission1 = $assign->get_user_submission($student->id, true, 0);
+        $submission2 = $assign->get_user_submission($student->id, true, 1);
         $submission2->status = ASSIGN_SUBMISSION_STATUS_REOPENED;
-        $assign->testable_update_submission($submission2, $this->students[0]->id, time(), $assign->get_instance()->teamsubmission);
+        $assign->testable_update_submission($submission2, $student->id, time(), $assign->get_instance()->teamsubmission);
 
         $sink = $this->redirectEvents();
         $notices = null;
@@ -487,7 +531,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_duplicated', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($submission2->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->userid);
+        $this->assertEquals($student->id, $event->userid);
         $submission2->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
         $expected = array(
             $assign->get_course()->id,
@@ -502,13 +546,19 @@ class assign_events_testcase extends mod_assign_base_testcase {
     }
 
     public function test_submission_unlocked() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
         $sink = $this->redirectEvents();
 
-        $assign->unlock_submission($this->students[0]->id);
+        $assign->unlock_submission($student->id);
 
         $events = $sink->get_events();
         $this->assertCount(1, $events);
@@ -516,35 +566,39 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_unlocked', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $expected = array(
             $assign->get_course()->id,
             'assign',
             'unlock submission',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('unlocksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
+            get_string('unlocksubmissionforstudent', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student))),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     public function test_submission_graded() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
 
         // Test apply_grade_to_user.
         $sink = $this->redirectEvents();
 
         $data = new stdClass();
         $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
-        $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
+        $assign->testable_apply_grade_to_user($data, $student->id, 0);
+        $grade = $assign->get_user_grade($student->id, false, 0);
 
         $events = $sink->get_events();
         $this->assertCount(3, $events);
@@ -552,7 +606,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($grade->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $expected = array(
             $assign->get_course()->id,
             'assign',
@@ -567,14 +621,14 @@ class assign_events_testcase extends mod_assign_base_testcase {
         // Test process_save_quick_grades.
         $sink = $this->redirectEvents();
 
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $data = array(
-            'grademodified_' . $this->students[0]->id => time(),
-            'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
-            'quickgrade_' . $this->students[0]->id => '60.0'
+            'grademodified_' . $student->id => time(),
+            'gradeattempt_' . $student->id => $grade->attemptnumber,
+            'quickgrade_' . $student->id => '60.0'
         );
         $assign->testable_process_save_quick_grades($data);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertEquals('60.0', $grade->grade);
 
         $events = $sink->get_events();
@@ -583,7 +637,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($grade->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $expected = array(
             $assign->get_course()->id,
             'assign',
@@ -600,7 +654,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $data = clone($grade);
         $data->grade = '50.0';
         $assign->update_grade($data);
-        $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
+        $grade = $assign->get_user_grade($student->id, false, 0);
         $this->assertEquals('50.0', $grade->grade);
         $events = $sink->get_events();
 
@@ -609,7 +663,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
         $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
         $this->assertEquals($assign->get_context(), $event->get_context());
         $this->assertEquals($grade->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($student->id, $event->relateduserid);
         $expected = array(
             $assign->get_course()->id,
             'assign',
@@ -620,8 +674,6 @@ class assign_events_testcase extends mod_assign_base_testcase {
         );
         $this->assertEventLegacyLogData($expected, $event);
         $sink->close();
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
     }
 
     /**
@@ -630,10 +682,16 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_submission_viewed() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
 
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
+        $submission = $assign->get_user_submission($student->id, true);
 
         // We need to set the URL in order to view the submission.
         $PAGE->set_url('/a_url');
@@ -659,7 +717,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
             'assign',
             'view submission',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('viewsubmissionforuser', 'assign', $this->students[0]->id),
+            get_string('viewsubmissionforuser', 'assign', $student->id),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -672,15 +730,21 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_feedback_viewed() {
         global $DB, $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
+        $submission = $assign->get_user_submission($student->id, true);
 
         // Insert a grade for this submission.
         $grade = new stdClass();
         $grade->assignment = $assign->get_instance()->id;
-        $grade->userid = $this->students[0]->id;
+        $grade->userid = $student->id;
         $gradeid = $DB->insert_record('assign_grades', $grade);
 
         // We need to set the URL in order to view the feedback.
@@ -708,7 +772,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
             'assign',
             'view feedback',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('viewfeedbackforuser', 'assign', $this->students[0]->id),
+            get_string('viewfeedbackforuser', 'assign', $student->id),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -721,16 +785,22 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_grading_form_viewed() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
 
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the feedback.
         $PAGE->set_url('/a_url');
         // A hack - this variable is used by the view_single_grade_page function.
         global $_POST;
         $_POST['rownum'] = 1;
-        $_POST['userid'] = $this->students[0]->id;
+        $_POST['userid'] = $student->id;
 
         // Trigger and capture the event.
         $sink = $this->redirectEvents();
@@ -747,8 +817,8 @@ class assign_events_testcase extends mod_assign_base_testcase {
             'assign',
             'view grading form',
             'view.php?id=' . $assign->get_course_module()->id,
-            get_string('viewgradingformforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
+            get_string('viewgradingformforstudent', 'assign', array('id' => $student->id,
+                'fullname' => fullname($student))),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -761,16 +831,22 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_grading_table_viewed() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
 
-        $assign = $this->create_instance();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the feedback.
         $PAGE->set_url('/a_url');
         // A hack - this variable is used by the view_single_grade_page function.
         global $_POST;
         $_POST['rownum'] = 1;
-        $_POST['userid'] = $this->students[0]->id;
+        $_POST['userid'] = $student->id;
 
         // Trigger and capture the event.
         $sink = $this->redirectEvents();
@@ -800,9 +876,14 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_submission_form_viewed() {
         global $PAGE;
 
-        $this->setUser($this->students[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $assign = $this->create_instance();
+        $this->setUser($student);
+
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the submission form.
         $PAGE->set_url('/a_url');
@@ -835,9 +916,14 @@ class assign_events_testcase extends mod_assign_base_testcase {
     public function test_submission_confirmation_form_viewed() {
         global $PAGE;
 
-        $this->setUser($this->students[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($student);
 
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the submission form.
         $PAGE->set_url('/a_url');
@@ -869,11 +955,13 @@ class assign_events_testcase extends mod_assign_base_testcase {
      */
     public function test_reveal_identities_confirmation_page_viewed() {
         global $PAGE;
+        $this->resetAfterTest();
 
         // Set to the admin user so we have the permission to reveal identities.
         $this->setAdminUser();
 
-        $assign = $this->create_instance();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
 
         // We need to set the URL in order to view the submission form.
         $PAGE->set_url('/a_url');
@@ -905,12 +993,17 @@ class assign_events_testcase extends mod_assign_base_testcase {
      */
     public function test_statement_accepted() {
         // We want to be a student so we can submit assignments.
-        $this->setUser($this->students[0]);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($student);
 
         // We do not want to send any messages to the student during the PHPUNIT test.
         set_config('submissionreceipts', false, 'assign');
 
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
 
         // Create the data we want to pass to the submit_for_grading function.
         $data = new stdClass();
@@ -933,7 +1026,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
             'view.php?id=' . $assign->get_course_module()->id,
             get_string('submissionstatementacceptedlog',
                 'mod_assign',
-                fullname($this->students[0])),
+                fullname($student)),
             $assign->get_course_module()->id
         );
         $this->assertEventLegacyLogData($expected, $event);
@@ -975,11 +1068,15 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * Test the batch_set_workflow_state_viewed event.
      */
     public function test_batch_set_workflow_state_viewed() {
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
 
         // Trigger and capture the event.
         $sink = $this->redirectEvents();
-        $assign->testable_view_batch_set_workflow_state($this->students[0]->id);
+        $assign->testable_view_batch_set_workflow_state($student->id);
         $events = $sink->get_events();
         $event = reset($events);
 
@@ -1002,11 +1099,15 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * Test the batch_set_marker_allocation_viewed event.
      */
     public function test_batch_set_marker_allocation_viewed() {
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
 
         // Trigger and capture the event.
         $sink = $this->redirectEvents();
-        $assign->testable_view_batch_markingallocation($this->students[0]->id);
+        $assign->testable_view_batch_markingallocation($student->id);
         $events = $sink->get_events();
         $event = reset($events);
 
@@ -1032,9 +1133,10 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * create and trigger the event and ensure the event data is returned as expected.
      */
     public function test_user_override_created() {
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
-        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
+        $assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance(['course' => $course->id]);
 
         $params = array(
             'objectid' => 1,
@@ -1065,9 +1167,10 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * create and trigger the event and ensure the event data is returned as expected.
      */
     public function test_group_override_created() {
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
-        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
+        $assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance(['course' => $course->id]);
 
         $params = array(
             'objectid' => 1,
@@ -1098,9 +1201,10 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * create and trigger the event and ensure the event data is returned as expected.
      */
     public function test_user_override_updated() {
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
-        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
+        $assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance(['course' => $course->id]);
 
         $params = array(
             'objectid' => 1,
@@ -1131,9 +1235,10 @@ class assign_events_testcase extends mod_assign_base_testcase {
      * create and trigger the event and ensure the event data is returned as expected.
      */
     public function test_group_override_updated() {
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
-        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
+        $assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance(['course' => $course->id]);
 
         $params = array(
             'objectid' => 1,
@@ -1162,6 +1267,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
      */
     public function test_user_override_deleted() {
         global $DB;
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
         $assigninstance = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
@@ -1192,6 +1298,7 @@ class assign_events_testcase extends mod_assign_base_testcase {
      */
     public function test_group_override_deleted() {
         global $DB;
+        $this->resetAfterTest();
 
         $course = $this->getDataGenerator()->create_course();
         $assigninstance = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
index 1e9923e..49a13ac 100644 (file)
@@ -19,6 +19,8 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 
 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/mod/assign/externallib.php');
+require_once(__DIR__ . '/fixtures/testable_assign.php');
 
 /**
  * External mod assign functions unit tests
@@ -30,14 +32,6 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  */
 class mod_assign_external_testcase extends externallib_advanced_testcase {
 
-    /**
-     * Tests set up
-     */
-    protected function setUp() {
-        global $CFG;
-        require_once($CFG->dirroot . '/mod/assign/externallib.php');
-    }
-
     /**
      * Test get_grades
      */
@@ -1825,8 +1819,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
      * @return array an array containing all the required data for testing
      */
     private function create_submission_for_testing_status($submitforgrading = false) {
-        global $DB, $CFG;
-        require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+        global $DB;
 
         // Create a course and assignment and users.
         $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1));
@@ -1854,7 +1847,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
         $cm = get_coursemodule_from_instance('assign', $instance->id);
         $context = context_module::instance($cm->id);
 
-        $assign = new testable_assign($context, $cm, $course);
+        $assign = new mod_assign_testable_assign($context, $cm, $course);
 
         $student1 = self::getDataGenerator()->create_user();
         $student2 = self::getDataGenerator()->create_user();
@@ -2362,8 +2355,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
      * submitted.
      */
     public function test_get_participant_group_submission() {
-        global $DB, $CFG;
-        require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+        global $DB;
 
         $this->resetAfterTest(true);
 
@@ -2380,7 +2372,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
         $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
         $cm = get_coursemodule_from_instance('assign', $assignmodule->id);
         $context = context_module::instance($cm->id);
-        $assign = new testable_assign($context, $cm, $course);
+        $assign = new mod_assign_testable_assign($context, $cm, $course);
 
         groups_add_member($group, $student);
 
diff --git a/mod/assign/tests/fixtures/testable_assign.php b/mod/assign/tests/fixtures/testable_assign.php
new file mode 100644 (file)
index 0000000..e9adbab
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The testable assign class.
+ *
+ * @package   mod_assign
+ * @copyright 2014 Adrian Greeve <adrian@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+/**
+ * Test subclass that makes all the protected methods we want to test public.
+ */
+class mod_assign_testable_assign extends assign {
+
+    public function testable_show_intro() {
+        return parent::show_intro();
+    }
+
+    public function testable_delete_grades() {
+        return parent::delete_grades();
+    }
+
+    public function testable_apply_grade_to_user($formdata, $userid, $attemptnumber) {
+        return parent::apply_grade_to_user($formdata, $userid, $attemptnumber);
+    }
+
+    public function testable_format_submission_for_log(stdClass $submission) {
+        return parent::format_submission_for_log($submission);
+    }
+
+    public function testable_get_grading_userid_list() {
+        return parent::get_grading_userid_list();
+    }
+
+    public function testable_is_graded($userid) {
+        return parent::is_graded($userid);
+    }
+
+    public function testable_update_submission(stdClass $submission, $userid, $updatetime, $teamsubmission) {
+        return parent::update_submission($submission, $userid, $updatetime, $teamsubmission);
+    }
+
+    public function testable_process_add_attempt($userid = 0) {
+        return parent::process_add_attempt($userid);
+    }
+
+    public function testable_process_save_quick_grades($postdata) {
+        // Ugly hack to get something into the method.
+        global $_POST;
+        $_POST = $postdata;
+        return parent::process_save_quick_grades();
+    }
+
+    public function testable_process_set_batch_marking_allocation($selectedusers, $markerid) {
+        global $CFG;
+        require_once($CFG->dirroot . '/mod/assign/batchsetallocatedmarkerform.php');
+
+        // Simulate the form submission.
+        $data = array();
+        $data['id'] = $this->get_course_module()->id;
+        $data['selectedusers'] = $selectedusers;
+        $data['allocatedmarker'] = $markerid;
+        $data['action'] = 'setbatchmarkingallocation';
+        mod_assign_batch_set_allocatedmarker_form::mock_submit($data);
+
+        return parent::process_set_batch_marking_allocation();
+    }
+
+    public function testable_process_set_batch_marking_workflow_state($selectedusers, $state) {
+        global $CFG;
+        require_once($CFG->dirroot . '/mod/assign/batchsetmarkingworkflowstateform.php');
+
+        // Simulate the form submission.
+        $data = array();
+        $data['id'] = $this->get_course_module()->id;
+        $data['selectedusers'] = $selectedusers;
+        $data['markingworkflowstate'] = $state;
+        $data['action'] = 'setbatchmarkingworkflowstate';
+        mod_assign_batch_set_marking_workflow_state_form::mock_submit($data);
+
+        return parent::process_set_batch_marking_workflow_state();
+    }
+
+    public function testable_submissions_open($userid = 0) {
+        return parent::submissions_open($userid);
+    }
+
+    public function testable_save_user_extension($userid, $extensionduedate) {
+        return parent::save_user_extension($userid, $extensionduedate);
+    }
+
+    public function testable_get_graders($userid) {
+        // Changed method from protected to public.
+        return parent::get_graders($userid);
+    }
+
+    public function testable_get_notifiable_users($userid) {
+        return parent::get_notifiable_users($userid);
+    }
+
+    public function testable_view_batch_set_workflow_state($selectedusers) {
+        global $PAGE;
+        $PAGE->set_url('/mod/assign/view.php');
+        $mform = $this->testable_grading_batch_operations_form('setmarkingworkflowstate', $selectedusers);
+        return parent::view_batch_set_workflow_state($mform);
+    }
+
+    public function testable_view_batch_markingallocation($selectedusers) {
+        global $PAGE;
+        $PAGE->set_url('/mod/assign/view.php');
+        $mform = $this->testable_grading_batch_operations_form('setmarkingallocation', $selectedusers);
+        return parent::view_batch_markingallocation($mform);
+    }
+
+    public function testable_grading_batch_operations_form($operation, $selectedusers) {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
+
+        // Mock submit the grading operations form.
+        $data = array();
+        $data['id'] = $this->get_course_module()->id;
+        $data['selectedusers'] = $selectedusers;
+        $data['returnaction'] = 'grading';
+        $data['operation'] = $operation;
+        mod_assign_grading_batch_operations_form::mock_submit($data);
+
+        // Set required variables in the form.
+        $formparams = array();
+        $formparams['submissiondrafts'] = 1;
+        $formparams['duedate'] = 1;
+        $formparams['attemptreopenmethod'] = ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL;
+        $formparams['feedbackplugins'] = array();
+        $formparams['markingworkflow'] = 1;
+        $formparams['markingallocation'] = 1;
+        $formparams['cm'] = $this->get_course_module()->id;
+        $formparams['context'] = $this->get_context();
+        $mform = new mod_assign_grading_batch_operations_form(null, $formparams);
+
+        return $mform;
+    }
+
+    public function testable_update_activity_completion_records($teamsubmission,
+                                                          $requireallteammemberssubmit,
+                                                          $submission,
+                                                          $userid,
+                                                          $complete,
+                                                          $completion) {
+        return parent::update_activity_completion_records($teamsubmission,
+                                                          $requireallteammemberssubmit,
+                                                          $submission,
+                                                          $userid,
+                                                          $complete,
+                                                          $completion);
+    }
+}
diff --git a/mod/assign/tests/generator.php b/mod/assign/tests/generator.php
new file mode 100644 (file)
index 0000000..ba28665
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Base class for unit tests for mod_assign.
+ *
+ * @package    mod_assign
+ * @category   phpunit
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/locallib.php');
+require_once(__DIR__ . '/fixtures/testable_assign.php');
+
+/**
+ * Generator helper trait.
+ *
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+trait mod_assign_test_generator {
+
+    /**
+     * Convenience function to create a testable instance of an assignment.
+     *
+     * @param array $params Array of parameters to pass to the generator
+     * @return testable_assign Testable wrapper around the assign class.
+     */
+    protected function create_instance($course, $params = [], $options = []) {
+        $params['course'] = $course->id;
+
+        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $generator->create_instance($params, $options);
+        $cm = get_coursemodule_from_instance('assign', $instance->id);
+        $context = context_module::instance($cm->id);
+
+        return new mod_assign_testable_assign($context, $cm, $course);
+    }
+
+    /**
+     * Add a user submission to the assignment.
+     *
+     * @param   \stdClass   $student The user to submit for
+     * @param   \assign     $assign The assignment to submit to
+     * @param   string      $onlinetext The text tobe submitted
+     * @param   bool        $changeuser Whether to switch user to the user being submitted as.
+     */
+    protected function add_submission($student, $assign, $onlinetext = null, $changeuser = true) {
+        // Add a submission.
+        if ($changeuser) {
+            $this->setUser($student);
+        }
+
+        if ($onlinetext === null) {
+            $onlinetext = 'Submission text';
+        }
+
+        $data = (object) [
+            'userid' => $student->id,
+
+            'onlinetext_editor' => [
+                'itemid' => file_get_unused_draft_itemid(),
+                'text' => $onlinetext,
+                'format' => FORMAT_HTML,
+            ]
+        ];
+
+        $assign->save_submission($data, $notices);
+    }
+
+    /**
+     * Submit the assignemnt for grading.
+     *
+     * @param   \stdClass   $student The user to submit for
+     * @param   \assign     $assign The assignment to submit to
+     * @param   array       $data Additional data to set
+     * @param   bool        $changeuser Whether to switch user to the user being submitted as.
+     */
+    public function submit_for_grading($student, $assign, $data = [], $changeuser = true) {
+        if ($changeuser) {
+            $this->setUser($student);
+        }
+
+        $data = (object) array_merge($data, [
+                'userid' => $student->id,
+            ]);
+
+        $sink = $this->redirectMessages();
+        $assign->submit_for_grading($data, []);
+        $sink->close();
+
+        return $data;
+    }
+
+    /**
+     * Mark the submission.
+     *
+     * @param   \stdClass   $teacher The user to mark as
+     * @param   \assign     $assign The assignment to mark
+     * @param   \stdClass   $student The user to grade
+     * @param   array       $data Additional data to set
+     * @param   bool        $changeuser Whether to switch user to the user being submitted as.
+     */
+    protected function mark_submission($teacher, $assign, $student, $grade = 50.0, $data = [], $attempt = 0) {
+        // Mark the submission.
+        $this->setUser($teacher);
+        $data = (object) array_merge($data, [
+                'grade' => $grade,
+            ]);
+
+        $assign->testable_apply_grade_to_user($data, $student->id, $attempt);
+    }
+}
index cadf766..042ef54 100644 (file)
@@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 require_once($CFG->dirroot . '/mod/assign/lib.php');
 require_once($CFG->dirroot . '/mod/assign/locallib.php');
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 use \core_calendar\local\api as calendar_local_api;
 use \core_calendar\local\event\container as calendar_event_container;
@@ -40,135 +40,106 @@ use \core_calendar\local\event\container as calendar_event_container;
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class mod_assign_lib_testcase extends mod_assign_base_testcase {
-
-    protected function setUp() {
-        parent::setUp();
-
-        // Add additional default data (some real attempts and stuff).
-        $this->setUser($this->editingteachers[0]);
-        $this->create_instance();
-        $assign = $this->create_instance(array('duedate' => time(),
-                                               'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
-                                               'maxattempts' => 3,
-                                               'submissiondrafts' => 1,
-                                               'assignsubmission_onlinetext_enabled' => 1));
-
-        // Add a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
-                                         'text' => 'Submission text',
-                                         'format' => FORMAT_HTML);
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
-
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-
-        // Mark the submission.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
-
-        // This is required so that the submissions timemodified > the grade timemodified.
-        $this->waitForSecond();
-
-        // Edit the submission again.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-
-        // This is required so that the submissions timemodified > the grade timemodified.
-        $this->waitForSecond();
-
-        // Allow the student another attempt.
-        $this->teachers[0]->ignoresesskey = true;
-        $this->setUser($this->teachers[0]);
-        $result = $assign->testable_process_add_attempt($this->students[0]->id);
-        // Add another submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
-                                         'text' => 'Submission text 2',
-                                         'format' => FORMAT_HTML);
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
-
-        // And now submit it for marking (again).
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-    }
+
+class mod_assign_lib_testcase extends advanced_testcase {
+
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     public function test_assign_print_overview() {
         global $DB;
 
-        // Create one more assignment instance.
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
-        $courses = $DB->get_records('course', array('id' => $this->course->id));
+
+        // Assignment with default values.
+        $firstassign = $this->create_instance($course, ['name' => 'First Assignment']);
+
+        // Assignment with submissions.
+        $secondassign = $this->create_instance($course, [
+                'name' => 'Assignment with submissions',
+                'duedate' => time(),
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
+                'maxattempts' => 3,
+                'submissiondrafts' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $this->add_submission($student, $secondassign);
+        $this->submit_for_grading($student, $secondassign);
+        $this->mark_submission($teacher, $secondassign, $student, 50.0);
+
         // Past assignments should not show up.
-        $pastassign = $this->create_instance(array('duedate' => time() - 370001,
-                                                   'cutoffdate' => time() - 370000,
-                                                   'nosubmissions' => 0,
-                                                   'assignsubmission_onlinetext_enabled' => 1));
+        $pastassign = $this->create_instance($course, [
+                'name' => 'Past Assignment',
+                'duedate' => time() - DAYSECS - 1,
+                'cutoffdate' => time() - DAYSECS,
+                'nosubmissions' => 0,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+
         // Open assignments should show up only if relevant.
-        $openassign = $this->create_instance(array('duedate' => time(),
-                                                   'cutoffdate' => time() + 370000,
-                                                   'nosubmissions' => 0,
-                                                   'assignsubmission_onlinetext_enabled' => 1));
-        $pastsubmission = $pastassign->get_user_submission($this->students[0]->id, true);
-        $opensubmission = $openassign->get_user_submission($this->students[0]->id, true);
+        $openassign = $this->create_instance($course, [
+                'name' => 'Open Assignment',
+                'duedate' => time(),
+                'cutoffdate' => time() + DAYSECS,
+                'nosubmissions' => 0,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $pastsubmission = $pastassign->get_user_submission($student->id, true);
+        $opensubmission = $openassign->get_user_submission($student->id, true);
 
         // Check the overview as the different users.
         // For students , open assignments should show only when there are no valid submissions.
-        $this->setUser($this->students[0]);
+        $this->setUser($student);
         $overview = array();
+        $courses = $DB->get_records('course', array('id' => $course->id));
         assign_print_overview($courses, $overview);
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(1, count($overview));
-        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); // No valid submission.
-        $this->assertNotRegExp('/.*Assignment 1.*/', $overview[$this->course->id]['assign']); // Has valid submission.
+        $this->assertRegExp('/.*Open Assignment.*/', $overview[$course->id]['assign']); // No valid submission.
+        $this->assertNotRegExp('/.*First Assignment.*/', $overview[$course->id]['assign']); // Has valid submission.
 
         // And now submit the submission.
         $opensubmission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $openassign->testable_update_submission($opensubmission, $this->students[0]->id, true, false);
+        $openassign->testable_update_submission($opensubmission, $student->id, true, false);
 
         $overview = array();
         assign_print_overview($courses, $overview);
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(0, count($overview));
 
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $overview = array();
         assign_print_overview($courses, $overview);
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(1, count($overview));
         // Submissions without a grade.
-        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
-        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Open Assignment.*/', $overview[$course->id]['assign']);
+        $this->assertRegExp('/.*Assignment with submissions.*/', $overview[$course->id]['assign']);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $overview = array();
         assign_print_overview($courses, $overview);
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(1, count($overview));
         // Submissions without a grade.
-        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
-        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Open Assignment.*/', $overview[$course->id]['assign']);
+        $this->assertRegExp('/.*Assignment with submissions.*/', $overview[$course->id]['assign']);
 
         // Let us grade a submission.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $data = new stdClass();
         $data->grade = '50.0';
-        $openassign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $openassign->testable_apply_grade_to_user($data, $student->id, 0);
 
         // The assign_print_overview expects the grade date to be after the submission date.
         $graderecord = $DB->get_record('assign_grades', array('assignment' => $openassign->get_instance()->id,
-            'userid' => $this->students[0]->id, 'attemptnumber' => 0));
+            'userid' => $student->id, 'attemptnumber' => 0));
         $graderecord->timemodified += 1;
         $DB->update_record('assign_grades', $graderecord);
 
@@ -177,170 +148,200 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(1, count($overview));
         // Now assignment 4 should not show up.
-        $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
-        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+        $this->assertNotRegExp('/.*Open Assignment.*/', $overview[$course->id]['assign']);
+        $this->assertRegExp('/.*Assignment with submissions.*/', $overview[$course->id]['assign']);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $overview = array();
         assign_print_overview($courses, $overview);
         $this->assertDebuggingCalledCount(3);
         $this->assertEquals(1, count($overview));
         // Now assignment 4 should not show up.
-        $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
-        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+        $this->assertNotRegExp('/.*Open Assignment.*/', $overview[$course->id]['assign']);
+        $this->assertRegExp('/.*Assignment with submissions.*/', $overview[$course->id]['assign']);
+    }
 
-        // Open offline assignments should not show any notification to students.
-        $openassign = $this->create_instance(array('duedate' => time(),
-                                                   'cutoffdate' => time() + 370000));
-        $this->setUser($this->students[0]);
-        $overview = array();
-        assign_print_overview($courses, $overview);
-        $this->assertDebuggingCalledCount(4);
+    /**
+     * Test that assign_print_overview does not return any assignments which are Open Offline.
+     */
+    public function test_assign_print_overview_open_offline() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setAdminUser();
+        $openassign = $this->create_instance($course, [
+                'duedate' => time() + DAYSECS,
+                'cutoffdate' => time() + (DAYSECS * 2),
+            ]);
+
+        $this->setUser($student);
+        $overview = [];
+        assign_print_overview([$course], $overview);
+
+        $this->assertDebuggingCalledCount(1);
         $this->assertEquals(0, count($overview));
     }
 
+    /**
+     * Test that assign_print_recent_activity shows ungraded submitted assignments.
+     */
     public function test_print_recent_activity() {
-        // Submitting an assignment generates a notification.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
-
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $notices = array();
-        $this->setUser($this->students[0]);
-        $assign->submit_for_grading($data, $notices);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $this->submit_for_grading($student, $assign);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $this->expectOutputRegex('/submitted:/');
-        assign_print_recent_activity($this->course, true, time() - 3600);
-
-        $sink->close();
+        assign_print_recent_activity($course, true, time() - 3600);
     }
 
-    /** Make sure fullname dosn't trigger any warnings when assign_print_recent_activity is triggered. */
+    /**
+     * Test that assign_print_recent_activity does not display any warnings when a custom fullname has been configured.
+     */
     public function test_print_recent_activity_fullname() {
-        // Submitting an assignment generates a notification.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
-
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $notices = array();
-        $this->setUser($this->students[0]);
-        $assign->submit_for_grading($data, $notices);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $this->submit_for_grading($student, $assign);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $this->expectOutputRegex('/submitted:/');
         set_config('fullnamedisplay', 'firstname, lastnamephonetic');
-        assign_print_recent_activity($this->course, false, time() - 3600);
-
-        $sink->close();
+        assign_print_recent_activity($course, false, time() - 3600);
     }
 
-    /** Make sure blind marking shows participant \d+ not fullname when assign_print_recent_activity is triggered. */
+    /**
+     * Test that assign_print_recent_activity shows the blind marking ID.
+     */
     public function test_print_recent_activity_fullname_blind_marking() {
-        // Submitting an assignment generates a notification in blind marking.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
-
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('blindmarking' => 1));
-
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $notices = array();
-        $this->setUser($this->students[0]);
-        $assign->submit_for_grading($data, $notices);
-
-        $this->setUser($this->editingteachers[0]);
-        $uniqueid = $assign->get_uniqueid_for_user($data->userid);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'blindmarking' => 1,
+            ]);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+
+        $this->setUser($teacher);
+        $uniqueid = $assign->get_uniqueid_for_user($student->id);
         $expectedstr = preg_quote(get_string('participant', 'mod_assign'), '/') . '.*' . $uniqueid;
         $this->expectOutputRegex("/{$expectedstr}/");
-        assign_print_recent_activity($this->course, false, time() - 3600);
-
-        $sink->close();
+        assign_print_recent_activity($course, false, time() - 3600);
     }
 
+    /**
+     * Test that assign_get_recent_mod_activity fetches the assignment correctly.
+     */
     public function test_assign_get_recent_mod_activity() {
-        // Submitting an assignment generates a notification.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+
+        $index = 1;
+        $activities = [
+            $index => (object) [
+                'type' => 'assign',
+                'cmid' => $assign->get_course_module()->id,
+            ],
+        ];
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->setUser($teacher);
+        assign_get_recent_mod_activity($activities, $index, time() - HOURSECS, $course->id, $assign->get_course_module()->id);
 
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $notices = array();
-        $this->setUser($this->students[0]);
-        $assign->submit_for_grading($data, $notices);
-
-        $this->setUser($this->editingteachers[0]);
-        $activities = array();
-        $index = 0;
-
-        $activity = new stdClass();
-        $activity->type    = 'activity';
-        $activity->cmid    = $assign->get_course_module()->id;
-        $activities[$index++] = $activity;
-
-        assign_get_recent_mod_activity( $activities,
-                                        $index,
-                                        time() - 3600,
-                                        $this->course->id,
-                                        $assign->get_course_module()->id);
-
-        $this->assertEquals("assign", $activities[1]->type);
-        $sink->close();
+        $activity = $activities[1];
+        $this->assertEquals("assign", $activity->type);
+        $this->assertEquals($student->id, $activity->user->id);
     }
 
+    /**
+     * Ensure that assign_user_complete displays information about drafts.
+     */
     public function test_assign_user_complete() {
         global $PAGE, $DB;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('submissiondrafts' => 1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, ['submissiondrafts' => 1]);
+        $this->add_submission($student, $assign);
+
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
 
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
         $DB->update_record('assign_submission', $submission);
 
         $this->expectOutputRegex('/Draft/');
-        assign_user_complete($this->course, $this->students[0], $assign->get_course_module(), $assign->get_instance());
+        assign_user_complete($course, $student, $assign->get_course_module(), $assign->get_instance());
     }
 
+    /**
+     * Ensure that assign_user_outline fetches updated grades.
+     */
     public function test_assign_user_outline() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
 
-        $this->setUser($this->teachers[0]);
-        $data = $assign->get_user_grade($this->students[0]->id, true);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
+
+        $this->setUser($teacher);
+        $data = $assign->get_user_grade($student->id, true);
         $data->grade = '50.5';
         $assign->update_grade($data);
 
-        $result = assign_user_outline($this->course, $this->students[0], $assign->get_course_module(), $assign->get_instance());
+        $result = assign_user_outline($course, $student, $assign->get_course_module(), $assign->get_instance());
 
         $this->assertRegExp('/50.5/', $result->info);
     }
 
+    /**
+     * Ensure that assign_get_completion_state reflects the correct status at each point.
+     */
     public function test_assign_get_completion_state() {
         global $DB;
-        $assign = $this->create_instance(array('submissiondrafts' => 0, 'completionsubmit' => 1));
 
-        $this->setUser($this->students[0]);
-        $result = assign_get_completion_state($this->course, $assign->get_course_module(), $this->students[0]->id, false);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'submissiondrafts' => 0,
+                'completionsubmit' => 1
+            ]);
+
+        $this->setUser($student);
+        $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false);
         $this->assertFalse($result);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $DB->update_record('assign_submission', $submission);
 
-        $result = assign_get_completion_state($this->course, $assign->get_course_module(), $this->students[0]->id, false);
+        $this->add_submission($student, $assign);
+        $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false);
+        $this->assertFalse($result);
 
+        $this->submit_for_grading($student, $assign);
+        $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false);
+        $this->assertTrue($result);
+
+        $this->mark_submission($teacher, $assign, $student, 50.0);
+        $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false);
         $this->assertTrue($result);
     }
 
@@ -349,38 +350,47 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
      */
     public function test_assign_refresh_events() {
         global $DB;
+
+        $this->resetAfterTest();
+
         $duedate = time();
         $newduedate = $duedate + DAYSECS;
+
         $this->setAdminUser();
 
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, [
+                'duedate' => $duedate,
+            ]);
 
-        // Make sure the calendar event for assignment 1 matches the initial due date.
         $instance = $assign->get_instance();
         $eventparams = ['modulename' => 'assign', 'instance' => $instance->id];
+
+        // Make sure the calendar event for assignment 1 matches the initial due date.
         $eventtime = $DB->get_field('event', 'timestart', $eventparams, MUST_EXIST);
         $this->assertEquals($eventtime, $duedate);
 
         // Manually update assignment 1's due date.
-        $DB->update_record('assign', (object)['id' => $instance->id, 'duedate' => $newduedate]);
+        $DB->update_record('assign', (object) ['id' => $instance->id, 'duedate' => $newduedate]);
 
         // Then refresh the assignment events of assignment 1's course.
-        $this->assertTrue(assign_refresh_events($this->course->id));
+        $this->assertTrue(assign_refresh_events($course->id));
 
         // Confirm that the assignment 1's due date event now has the new due date after refresh.
         $eventtime = $DB->get_field('event', 'timestart', $eventparams, MUST_EXIST);
         $this->assertEquals($eventtime, $newduedate);
 
         // Create a second course and assignment.
-        $generator = $this->getDataGenerator();
-        $course2 = $generator->create_course();
-        $assign2 = $this->create_instance(['duedate' => $duedate, 'course' => $course2->id]);
-        $instance2 = $assign2->get_instance();
+        $othercourse = $this->getDataGenerator()->create_course();;
+        $otherassign = $this->create_instance($othercourse, ['duedate' => $duedate, 'course' => $othercourse->id]);
+        $otherinstance = $otherassign->get_instance();
 
         // Manually update assignment 1 and 2's due dates.
         $newduedate += DAYSECS;
         $DB->update_record('assign', (object)['id' => $instance->id, 'duedate' => $newduedate]);
-        $DB->update_record('assign', (object)['id' => $instance2->id, 'duedate' => $newduedate]);
+        $DB->update_record('assign', (object)['id' => $otherinstance->id, 'duedate' => $newduedate]);
 
         // Refresh events of all courses.
         $this->assertTrue(assign_refresh_events());
@@ -390,12 +400,12 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         $this->assertEquals($eventtime, $newduedate);
 
         // Check the due date calendar event for assignment 2.
-        $eventparams['instance'] = $instance2->id;
+        $eventparams['instance'] = $otherinstance->id;
         $eventtime = $DB->get_field('event', 'timestart', $eventparams, MUST_EXIST);
         $this->assertEquals($eventtime, $newduedate);
 
         // In case the course ID is passed as a numeric string.
-        $this->assertTrue(assign_refresh_events('' . $this->course->id));
+        $this->assertTrue(assign_refresh_events('' . $course->id));
 
         // Non-existing course ID.
         $this->assertFalse(assign_refresh_events(-1));
@@ -405,85 +415,81 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_assign_core_calendar_is_event_visible_duedate_event_as_teacher() {
-        $this->setAdminUser();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $assign = $this->create_instance($course);
 
-        // Create an assignment.
-        $assign = $this->create_instance();
+        $this->setAdminUser();
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_DUE);
-
-        // Set the user to a teacher.
-        $this->setUser($this->editingteachers[0]);
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
 
         // The teacher should see the due date event.
+        $this->setUser($teacher);
         $this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
     }
 
     public function test_assign_core_calendar_is_event_visible_duedate_event_as_student() {
-        $this->setAdminUser();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
 
-        // Create an assignment.
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
+        $this->setAdminUser();
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_DUE);
-
-        // Set the user to a student.
-        $this->setUser($this->students[0]);
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
 
         // The student should care about the due date event.
+        $this->setUser($student);
         $this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
     }
 
     public function test_assign_core_calendar_is_event_visible_gradingduedate_event_as_teacher() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $assign = $this->create_instance($course);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_GRADINGDUE);
-
-        // Set the user to a teacher.
-        $this->setUser($this->editingteachers[0]);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
 
-        // The teacher should care about the grading due date event.
+        // The teacher should see the due date event.
+        $this->setUser($teacher);
         $this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
     }
 
     public function test_assign_core_calendar_is_event_visible_gradingduedate_event_as_student() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_GRADINGDUE);
-
-        // Set the user to a student.
-        $this->setUser($this->students[0]);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
 
-        // The student should not care about the grading due date event.
+        // The student should not see the due date event.
+        $this->setUser($student);
         $this->assertFalse(mod_assign_core_calendar_is_event_visible($event));
     }
 
     public function test_assign_core_calendar_provide_event_action_duedate_as_teacher() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $assign = $this->create_instance($course);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_DUE);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
 
-        // Create an action factory.
+        // The teacher should see the event.
+        $this->setUser($teacher);
         $factory = new \core_calendar\action_factory();
-
-        // Set the user to a teacher.
-        $this->setUser($this->teachers[0]);
-
-        // Decorate action event.
         $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory);
 
         // The teacher should not have an action for a due date event.
@@ -491,21 +497,18 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_assign_core_calendar_provide_event_action_duedate_as_student() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_DUE);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
 
-        // Create an action factory.
+        // The student should see the event.
+        $this->setUser($student);
         $factory = new \core_calendar\action_factory();
-
-        // Set the user to a student.
-        $this->setUser($this->students[0]);
-
-        // Decorate action event.
         $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory);
 
         // Confirm the event was decorated.
@@ -517,21 +520,17 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_assign_core_calendar_provide_event_action_gradingduedate_as_teacher() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $assign = $this->create_instance($course);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_GRADINGDUE);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
 
-        // Create an action factory.
+        $this->setUser($teacher);
         $factory = new \core_calendar\action_factory();
-
-        // Set the user to a teacher.
-        $this->setUser($this->editingteachers[0]);
-
-        // Decorate action event.
         $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory);
 
         // Confirm the event was decorated.
@@ -543,21 +542,17 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_assign_core_calendar_provide_event_action_gradingduedate_as_student() {
-        $this->setAdminUser();
-
-        // Create an assignment.
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course);
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_GRADINGDUE);
+        $this->setAdminUser();
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
 
-        // Create an action factory.
+        $this->setUser($student);
         $factory = new \core_calendar\action_factory();
-
-        // Set the user to a student.
-        $this->setUser($this->students[0]);
-
-        // Decorate action event.
         $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory);
 
         // Confirm the event was decorated.
@@ -569,58 +564,44 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_assign_core_calendar_provide_event_action_duedate_as_student_submitted() {
-        $this->setAdminUser();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
 
-        // Create an assignment.
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
+        $this->setAdminUser();
 
         // Create a calendar event.
-        $event = $this->create_action_event($assign->get_instance()->id, ASSIGN_EVENT_TYPE_DUE);
+        $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
 
         // Create an action factory.
         $factory = new \core_calendar\action_factory();
 
-        // Set the user to a student.
-        $this->setUser($this->students[0]);
-
-        // Submit the assignment.
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-        $data = (object) [
-            'userid' => $this->students[0]->id,
-            'onlinetext_editor' => [
-                'itemid' => file_get_unused_draft_itemid(),
-                'text' => 'Submission text',
-                'format' => FORMAT_MOODLE,
-            ],
-        ];
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        // Submit as the student.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
-        // Create an action factory.
+        // Confirm there was no event to action.
         $factory = new \core_calendar\action_factory();
-
-        // Decorate action event.
         $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory);
-
-        // Confirm there was no event to action.
         $this->assertNull($actionevent);
     }
 
     /**
      * Creates an action event.
      *
-     * @param int $instanceid The assign id.
+     * @param \stdClass $course The course the assignment is in
+     * @param assign $assign The assignment to create an event for
      * @param string $eventtype The event type. eg. ASSIGN_EVENT_TYPE_DUE.
      * @return bool|calendar_event
      */
-    private function create_action_event($instanceid, $eventtype) {
+    private function create_action_event($course, $assign, $eventtype) {
         $event = new stdClass();
         $event->name = 'Calendar event';
         $event->modulename  = 'assign';
-        $event->courseid = $this->course->id;
-        $event->instance = $instanceid;
+        $event->courseid = $course->id;
+        $event->instance = $assign->get_instance()->id;
         $event->type = CALENDAR_EVENT_TYPE_ACTION;
         $event->eventtype = $eventtype;
         $event->timestart = time();
@@ -635,18 +616,25 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
      */
     public function test_mod_assign_completion_get_active_rule_descriptions() {
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
+
         $this->setAdminUser();
 
         // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
-        $cm1 = $this->create_instance(['completion' => '2', 'completionsubmit' => '1'])->get_course_module();
-        $cm2 = $this->create_instance(['completion' => '2', 'completionsubmit' => '0'])->get_course_module();
+        $cm1 = $this->create_instance($course, ['completion' => '2', 'completionsubmit' => '1'])->get_course_module();
+        $cm2 = $this->create_instance($course, ['completion' => '2', 'completionsubmit' => '0'])->get_course_module();
 
         // Data for the stdClass input type.
         // This type of input would occur when checking the default completion rules for an activity type, where we don't have
         // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
-        $moddefaults = new stdClass();
-        $moddefaults->customdata = ['customcompletionrules' => ['completionsubmit' => '1']];
-        $moddefaults->completion = 2;
+        $moddefaults = (object) [
+            'customdata' => [
+                'customcompletionrules' => [
+                    'completionsubmit' => '1',
+                ],
+            ],
+            'completion' => 2,
+        ];
 
         $activeruledescriptions = [get_string('completionsubmit', 'assign')];
         $this->assertEquals(mod_assign_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
@@ -660,28 +648,32 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
      */
     public function test_assign_rescale_activity_grades_some_unset() {
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // As a teacher...
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        // As a teacher.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
 
         // Grade the student.
         $data = ['grade' => 50];
-        $assign->testable_apply_grade_to_user((object)$data, $this->students[0]->id, 0);
+        $assign->testable_apply_grade_to_user((object)$data, $student->id, 0);
 
         // Try getting another students grade. This will give a grade of ASSIGN_GRADE_NOT_SET (-1).
-        $assign->get_user_grade($this->students[1]->id, true);
+        $assign->get_user_grade($otherstudent->id, true);
 
         // Rescale.
-        assign_rescale_activity_grades($this->course, $assign->get_course_module(), 0, 100, 0, 10);
+        assign_rescale_activity_grades($course, $assign->get_course_module(), 0, 100, 0, 10);
 
         // Get the grades for both students.
-        $student0grade = $assign->get_user_grade($this->students[0]->id, true);
-        $student1grade = $assign->get_user_grade($this->students[1]->id, true);
+        $studentgrade = $assign->get_user_grade($student->id, true);
+        $otherstudentgrade = $assign->get_user_grade($otherstudent->id, true);
 
         // Make sure the real grade is scaled, but the ASSIGN_GRADE_NOT_SET stays the same.
-        $this->assertEquals($student0grade->grade, 5);
-        $this->assertEquals($student1grade->grade, ASSIGN_GRADE_NOT_SET);
+        $this->assertEquals($studentgrade->grade, 5);
+        $this->assertEquals($otherstudentgrade->grade, ASSIGN_GRADE_NOT_SET);
     }
 
     /**
@@ -692,17 +684,19 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
-        $userid = 1234;
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
 
         $instance = $assign->get_instance();
         $event = new \calendar_event((object)[
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'userid' => $userid
+            'userid' => $student->id,
         ]);
 
         $this->assertFalse($assign->is_override_calendar_event($event));
@@ -716,11 +710,14 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
-        $userid = $this->students[0]->id;
+        $userid = $student->id;
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
 
         $instance = $assign->get_instance();
         $event = new \calendar_event((object)[
@@ -739,26 +736,28 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
-        $userid = 1234;
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
-        $assign2 = $this->create_instance(['duedate' => $duedate]);
-
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
         $instance = $assign->get_instance();
+
+        $otherassign = $this->create_instance($course, ['duedate' => $duedate]);
+        $otherinstance = $otherassign->get_instance();
+
         $event = new \calendar_event((object) [
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'userid' => $userid
+            'userid' => $student->id,
         ]);
 
-        $record = (object) [
-            'assignid' => $assign2->get_instance()->id,
-            'userid' => $userid
-        ];
-
-        $DB->insert_record('assign_overrides', $record);
+        $DB->insert_record('assign_overrides', (object) [
+                'assignid' => $otherinstance->id,
+                'userid' => $student->id,
+            ]);
 
         $this->assertFalse($assign->is_override_calendar_event($event));
     }
@@ -771,25 +770,26 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
-        $userid = 1234;
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
 
         $instance = $assign->get_instance();
         $event = new \calendar_event((object) [
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'userid' => $userid
+            'userid' => $student->id,
         ]);
 
-        $record = (object) [
-            'assignid' => $instance->id,
-            'userid' => $userid
-        ];
 
-        $DB->insert_record('assign_overrides', $record);
+        $DB->insert_record('assign_overrides', (object) [
+                'assignid' => $instance->id,
+                'userid' => $student->id,
+            ]);
 
         $this->assertTrue($assign->is_override_calendar_event($event));
     }
@@ -802,26 +802,25 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
         $instance = $assign->get_instance();
         $group = $this->getDataGenerator()->create_group(array('courseid' => $instance->course));
-        $groupid = $group->id;
 
         $event = new \calendar_event((object) [
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'groupid' => $groupid
+            'groupid' => $group->id,
         ]);
 
-        $record = (object) [
-            'assignid' => $instance->id,
-            'groupid' => $groupid
-        ];
-
-        $DB->insert_record('assign_overrides', $record);
+        $DB->insert_record('assign_overrides', (object) [
+                'assignid' => $instance->id,
+                'groupid' => $group->id,
+            ]);
 
         $this->assertTrue($assign->is_override_calendar_event($event));
     }
@@ -834,10 +833,12 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
         $instance = $assign->get_instance();
 
         $event = new \calendar_event((object) [
@@ -860,24 +861,26 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
         $duedate = time();
-        $assign = $this->create_instance(['duedate' => $duedate]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
         $instance = $assign->get_instance();
-        $userid = $this->students[0]->id;
 
         $event = new \calendar_event((object) [
             'courseid' => $instance->course,
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'userid' => $userid,
+            'userid' => $student->id,
             'eventtype' => ASSIGN_EVENT_TYPE_DUE
         ]);
 
         $record = (object) [
             'assignid' => $instance->id,
-            'userid' => $userid
+            'userid' => $student->id,
         ];
 
         $DB->insert_record('assign_overrides', $record);
@@ -896,16 +899,17 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
         $duedate = time();
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => $duedate,
             'allowsubmissionsfromdate' => 0,
             'cutoffdate' => 0,
         ]);
         $instance = $assign->get_instance();
-        $userid = $this->students[0]->id;
 
         $event = new \calendar_event((object) [
             'courseid' => $instance->course,
@@ -928,18 +932,19 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
         $duedate = time();
         $submissionsfromdate = $duedate - DAYSECS;
         $cutoffdate = $duedate + DAYSECS;
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => $duedate,
             'allowsubmissionsfromdate' => $submissionsfromdate,
             'cutoffdate' => $cutoffdate,
         ]);
         $instance = $assign->get_instance();
-        $userid = $this->students[0]->id;
 
         $event = new \calendar_event((object) [
             'courseid' => $instance->course,
@@ -963,9 +968,11 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => 0,
             'allowsubmissionsfromdate' => 0,
             'cutoffdate' => 0,
@@ -992,14 +999,13 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
         $this->setAdminUser();
 
         $duedate = time();
-        $assign = $this->create_instance([
-            'duedate' => $duedate
-        ]);
+        $assign = $this->create_instance($course, ['duedate' => $duedate]);
         $instance = $assign->get_instance();
-        $userid = $this->students[0]->id;
 
         $event = new \calendar_event((object) [
             'courseid' => $instance->course,
@@ -1022,12 +1028,15 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
         $duedate = time();
         $submissionsfromdate = $duedate - DAYSECS;
         $cutoffdate = $duedate + DAYSECS;
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => $duedate,
             'allowsubmissionsfromdate' => $submissionsfromdate,
             'cutoffdate' => $cutoffdate,
@@ -1056,32 +1065,34 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
         $duedate = time();
         $submissionsfromdate = $duedate - DAYSECS;
         $cutoffdate = $duedate + DAYSECS;
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => $duedate,
             'allowsubmissionsfromdate' => $submissionsfromdate,
             'cutoffdate' => $cutoffdate,
         ]);
         $instance = $assign->get_instance();
-        $userid = $this->students[0]->id;
 
         $event = new \calendar_event((object) [
             'courseid' => $instance->course,
             'modulename' => 'assign',
             'instance' => $instance->id,
-            'userid' => $userid,
+            'userid' => $student->id,
             'eventtype' => ASSIGN_EVENT_TYPE_DUE,
             'timestart' => $duedate + 1
         ]);
 
         $record = (object) [
             'assignid' => $instance->id,
-            'userid' => $userid,
-            'duedate' => $duedate + 1
+            'userid' => $student->id,
+            'duedate' => $duedate + 1,
         ];
 
         $DB->insert_record('assign_overrides', $record);
@@ -1100,13 +1111,16 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $this->setAdminUser();
 
         $duedate = time();
         $newduedate = $duedate + 1;
         $submissionsfromdate = $duedate - DAYSECS;
         $cutoffdate = $duedate + DAYSECS;
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'duedate' => $duedate,
             'allowsubmissionsfromdate' => $submissionsfromdate,
             'cutoffdate' => $cutoffdate,
@@ -1137,26 +1151,25 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $context = context_course::instance($course->id);
+
+        $roleid = $this->getDataGenerator()->create_role();
+        $role = $DB->get_record('role', ['id' => $roleid]);
+        $user = $this->getDataGenerator()->create_and_enrol($course, $role->shortname);
+
         $this->setAdminUser();
 
         $mapper = calendar_event_container::get_event_mapper();
-        $generator = $this->getDataGenerator();
-        $user = $generator->create_user();
-        $course = $generator->create_course();
-        $context = context_course::instance($course->id);
-        $roleid = $generator->create_role();
         $now = time();
         $duedate = (new DateTime())->setTimestamp($now);
         $newduedate = (new DateTime())->setTimestamp($now)->modify('+1 day');
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'course' => $course->id,
             'duedate' => $duedate->getTimestamp(),
         ]);
         $instance = $assign->get_instance();
 
-        $generator->enrol_user($user->id, $course->id, 'student');
-        $generator->role_assign($roleid, $user->id, $context->id);
-
         $record = $DB->get_record('event', [
             'courseid' => $course->id,
             'modulename' => 'assign',
@@ -1194,26 +1207,23 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
 
         $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $context = context_course::instance($course->id);
+        $user = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $roleid = $DB->get_field('role', 'id', ['shortname' => 'teacher']);
+
         $this->setAdminUser();
 
         $mapper = calendar_event_container::get_event_mapper();
-        $generator = $this->getDataGenerator();
-        $user = $generator->create_user();
-        $course = $generator->create_course();
-        $context = context_course::instance($course->id);
-        $roleid = $generator->create_role();
         $now = time();
         $duedate = (new DateTime())->setTimestamp($now);
         $newduedate = (new DateTime())->setTimestamp($now)->modify('+1 day');
-        $assign = $this->create_instance([
+        $assign = $this->create_instance($course, [
             'course' => $course->id,
             'duedate' => $duedate->getTimestamp(),
         ]);
         $instance = $assign->get_instance();
 
-        $generator->enrol_user($user->id, $course->id, 'teacher');
-        $generator->role_assign($roleid, $user->id, $context->id);
-
         $record = $DB->get_record('event', [
             'courseid' => $course->id,
             'modulename' => 'assign',
index 6ccc233..db8958a 100644 (file)
@@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 require_once($CFG->dirroot . '/mod/assign/locallib.php');
 require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
 
 /**
  * Unit tests for (some of) mod/assign/locallib.php.
@@ -37,23 +37,32 @@ require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class mod_assign_locallib_testcase extends mod_assign_base_testcase {
+class mod_assign_locallib_testcase extends advanced_testcase {
+
+    // Use the generator helper.
+    use mod_assign_test_generator;
 
     public function test_return_links() {
         global $PAGE;
-        $this->setUser($this->editingteachers[0]);
-        $returnaction = 'RETURNACTION';
-        $returnparams = array('param'=>'1');
-        $assign = $this->create_instance();
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
-        $assign->register_return_link($returnaction, $returnparams);
-        $this->assertEquals($returnaction, $assign->get_return_action());
-        $this->assertEquals($returnparams, $assign->get_return_params());
+
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
+        $assign = $this->create_instance($course);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        $assign->register_return_link('RETURNACTION', ['param' => 1]);
+        $this->assertEquals('RETURNACTION', $assign->get_return_action());
+        $this->assertEquals(['param' => 1], $assign->get_return_params());
     }
 
     public function test_get_feedback_plugins() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
         $installedplugins = array_keys(core_component::get_plugin_list('assignfeedback'));
 
         foreach ($assign->get_feedback_plugins() as $plugin) {
@@ -62,8 +71,12 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_get_submission_plugins() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
         $installedplugins = array_keys(core_component::get_plugin_list('assignsubmission'));
 
         foreach ($assign->get_submission_plugins() as $plugin) {
@@ -72,8 +85,13 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_is_blind_marking() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('blindmarking'=>1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['blindmarking' => 1]);
         $this->assertEquals(true, $assign->is_blind_marking());
 
         // Test cannot see student names.
@@ -83,31 +101,31 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
 
         // Test students cannot reveal identities.
         $nopermission = false;
-        $this->students[0]->ignoresesskey = true;
-        $this->setUser($this->students[0]);
+        $student->ignoresesskey = true;
+        $this->setUser($student);
         $this->expectException('required_capability_exception');
         $assign->reveal_identities();
-        $this->students[0]->ignoresesskey = false;
+        $student->ignoresesskey = false;
 
         // Test teachers cannot reveal identities.
         $nopermission = false;
-        $this->teachers[0]->ignoresesskey = true;
-        $this->setUser($this->teachers[0]);
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
         $this->expectException('required_capability_exception');
         $assign->reveal_identities();
-        $this->teachers[0]->ignoresesskey = false;
+        $teacher->ignoresesskey = false;
 
         // Test sesskey is required.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $this->expectException('moodle_exception');
         $assign->reveal_identities();
 
         // Test editingteacher can reveal identities if sesskey is ignored.
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
         $assign->reveal_identities();
         $this->assertEquals(false, $assign->is_blind_marking());
-        $this->editingteachers[0]->ignoresesskey = false;
+        $teacher->ignoresesskey = false;
 
         // Test student names are visible.
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
@@ -115,7 +133,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertEquals(false, strpos($output, get_string('hiddenuser', 'assign')));
 
         // Set this back to default.
-        $this->editingteachers[0]->ignoresesskey = false;
+        $teacher->ignoresesskey = false;
     }
 
     /**
@@ -154,9 +172,14 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
      * @param array $userprefs Array of user preferences and expected page sizes
      */
     public function test_get_assign_perpage($maxperpage, $userprefs) {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
         set_config('maxperpage', $maxperpage, 'assign');
         set_user_preference('assign_perpage', null);
         $this->assertEquals(10, $assign->get_assign_perpage());
@@ -172,13 +195,18 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_gradingtable_extension_due_date() {
         global $PAGE;
 
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         // Setup the assignment.
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array(
-            'assignsubmission_onlinetext_enabled'=>1,
-            'duedate' => time() - 4 * 24 * 60 * 60,
-         ));
+        $this->setUser($teacher);
+        $time = time();
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'duedate' => time() - (4 * DAYSECS),
+            ]);
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
             'id' => $assign->get_course_module()->id,
             'action' => 'grading',
@@ -188,30 +216,32 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
-        $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((4 * DAYSECS))), $output);
 
         // Grant an extension.
-        $extendedtime = time() + 2 * 24 * 60 * 60;
-        $assign->testable_save_user_extension($this->students[0]->id, $extendedtime);
+        $extendedtime = $time + (2 * DAYSECS);
+        $assign->testable_save_user_extension($student->id, $extendedtime);
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
         $this->assertContains(get_string('userextensiondate', 'assign', userdate($extendedtime)), $output);
 
         // Simulate a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $assign->testable_update_submission($submission, $student->id, true, false);
         $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
+        $data->onlinetext_editor = [
+            'itemid' => file_get_unused_draft_itemid(),
+            'text' => 'Submission text',
+            'format' => FORMAT_MOODLE,
+        ];
         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
         $plugin->save($submission, $data);
 
         // Verify output.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
@@ -224,14 +254,18 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_gradingtable_extension_date_calculation_for_lateness() {
         global $PAGE;
 
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         // Setup the assignment.
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $time = time();
-        $assign = $this->create_instance(array(
-            'assignsubmission_onlinetext_enabled'=>1,
-            'duedate' => $time - 4 * 24 * 60 * 60,
-         ));
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'duedate' => time() - (4 * DAYSECS),
+            ]);
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
             'id' => $assign->get_course_module()->id,
             'action' => 'grading',
@@ -242,52 +276,58 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
         $difftime = time() - $time;
-        $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60 + $difftime)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((4 * DAYSECS) + $difftime)), $output);
 
         // Grant an extension that is in the past.
-        $assign->testable_save_user_extension($this->students[0]->id, $time - 2 * 24 * 60 * 60);
+        $assign->testable_save_user_extension($student->id, $time - (2 * DAYSECS));
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
-        $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - (2 * DAYSECS))), $output);
         $difftime = time() - $time;
-        $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((2 * DAYSECS) + $difftime)), $output);
 
         // Simulate a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $assign->testable_update_submission($submission, $student->id, true, false);
         $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
+        $data->onlinetext_editor = [
+            'itemid' => file_get_unused_draft_itemid(),
+            'text' => 'Submission text',
+            'format' => FORMAT_MOODLE,
+        ];
         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
         $plugin->save($submission, $data);
         $submittedtime = time();
 
         // Verify output.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
-        $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - (2 * DAYSECS))), $output);
 
         $difftime = $submittedtime - $time;
-        $this->assertContains(get_string('submittedlateshort', 'assign', format_time(2*24*60*60 + $difftime)), $output);
+        $this->assertContains(get_string('submittedlateshort', 'assign', format_time((2 * DAYSECS) + $difftime)), $output);
     }
 
     public function test_gradingtable_status_rendering() {
         global $PAGE;
 
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         // Setup the assignment.
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $time = time();
-        $assign = $this->create_instance(array(
+        $assign = $this->create_instance($course, [
             'assignsubmission_onlinetext_enabled' => 1,
-            'duedate' => $time - 4 * 24 * 60 * 60,
-         ));
+            'duedate' => $time - (4 * DAYSECS),
+         ]);
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
             'id' => $assign->get_course_module()->id,
             'action' => 'grading',
@@ -298,21 +338,21 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $output = $assign->get_renderer()->render($gradingtable);
         $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
         $difftime = time() - $time;
-        $this->assertContains(get_string('overdue', 'assign', format_time(4 * 24 * 60 * 60 + $difftime)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((4 * DAYSECS) + $difftime)), $output);
 
         // Simulate a student viewing the assignment without submitting.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $assign->testable_update_submission($submission, $student->id, true, false);
         $submittedtime = time();
 
         // Verify output.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $difftime = $submittedtime - $time;
-        $this->assertContains(get_string('overdue', 'assign', format_time(4 * 24 * 60 * 60 + $difftime)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((4 * DAYSECS) + $difftime)), $output);
 
         $document = new DOMDocument();
         @$document->loadHTML($output);
@@ -327,35 +367,61 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_gradingtable_group_submissions_rendering() {
         global $PAGE;
 
-        $this->create_extra_users();
-        // Now verify group assignments.
-        $this->setUser($this->teachers[0]);
-        $assign = $this->create_instance(array(
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        groups_add_member($group, $teacher);
+
+        $students = [];
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $students[] = $student;
+        groups_add_member($group, $student);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $students[] = $student;
+        groups_add_member($group, $student);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $students[] = $student;
+        groups_add_member($group, $student);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $students[] = $student;
+        groups_add_member($group, $student);
+
+        // Verify group assignments.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
             'teamsubmission' => 1,
             'assignsubmission_onlinetext_enabled' => 1,
             'submissiondrafts' => 1,
             'requireallteammemberssubmit' => 0,
-        ));
+        ]);
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
             'id' => $assign->get_course_module()->id,
             'action' => 'grading',
         )));
 
         // Add a submission.
-        $this->setUser($this->extrastudents[0]);
+        $this->setUser($student);
         $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
+        $data->onlinetext_editor = [
+            'itemid' => file_get_unused_draft_itemid(),
+            'text' => 'Submission text',
+            'format' => FORMAT_MOODLE,
+        ];
         $notices = array();
         $assign->save_submission($data, $notices);
 
-        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
+        $submission = $assign->get_group_submission($student->id, 0, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
+        $assign->testable_update_submission($submission, $student->id, true, true);
 
         // Check output.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $gradingtable = new assign_grading_table($assign, 4, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
         $document = new DOMDocument();
@@ -371,8 +437,8 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c8"])')));
 
         // Check group.
-        $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c5"])'));
-        $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c5"])'));
+        $this->assertSame($group->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c5"])'));
+        $this->assertSame($group->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c5"])'));
 
         // Check submission text.
         $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c9"]/div/div)'));
@@ -384,42 +450,54 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_show_intro() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
         // Test whether we are showing the intro at the correct times.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('alwaysshowdescription'=>1));
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['alwaysshowdescription' => 1]);
 
         $this->assertEquals(true, $assign->testable_show_intro());
 
-        $tomorrow = time() + (24*60*60);
+        $tomorrow = time() + DAYSECS;
 
-        $assign = $this->create_instance(array('alwaysshowdescription'=>0,
-                                               'allowsubmissionsfromdate'=>$tomorrow));
+        $assign = $this->create_instance($course, [
+                'alwaysshowdescription' => 0,
+                'allowsubmissionsfromdate' => $tomorrow,
+            ]);
         $this->assertEquals(false, $assign->testable_show_intro());
-        $yesterday = time() - (24*60*60);
-        $assign = $this->create_instance(array('alwaysshowdescription'=>0,
-                                               'allowsubmissionsfromdate'=>$yesterday));
+        $yesterday = time() - DAYSECS;
+        $assign = $this->create_instance($course, [
+                'alwaysshowdescription' => 0,
+                'allowsubmissionsfromdate' => $yesterday,
+            ]);
         $this->assertEquals(true, $assign->testable_show_intro());
     }
 
     public function test_has_submissions_or_grades() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
         $instance = $assign->get_instance();
 
         // Should start empty.
         $this->assertEquals(false, $assign->has_submissions_or_grades());
 
         // Simulate a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
 
         // The submission is still new.
         $this->assertEquals(false, $assign->has_submissions_or_grades());
 
         // Submit the submission.
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $assign->testable_update_submission($submission, $student->id, true, false);
         $data = new stdClass();
         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
                                          'text'=>'Submission text',
@@ -429,78 +507,80 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
 
         // Now test again.
         $this->assertEquals(true, $assign->has_submissions_or_grades());
-        // Set this back to default.
-        $this->students[0]->ignoresesskey = false;
     }
 
     public function test_delete_grades() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
 
         // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $data = new stdClass();
         $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $assign->testable_apply_grade_to_user($data, $student->id, 0);
 
         // Now see if the data is in the gradebook.
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id);
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id);
 
         $this->assertNotEquals(0, count($gradinginfo->items));
 
         $assign->testable_delete_grades();
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id);
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id);
 
         $this->assertEquals(0, count($gradinginfo->items));
     }
 
     public function test_delete_instance() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
 
         // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $data = new stdClass();
         $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $assign->testable_apply_grade_to_user($data, $student->id, 0);
 
         // Simulate a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $this->add_submission($student, $assign);
 
         // Now try and delete.
+        $this->setUser($teacher);
         $this->assertEquals(true, $assign->delete_instance());
     }
 
     public function test_reset_userdata() {
         global $DB;
 
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $now = time();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
-                                               'duedate'=>$now));
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'duedate' => $now,
+            ]);
 
         // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
 
         // Simulate a submission.
-        $this->setUser($this->students[0]);
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
         $data = new stdClass();
         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
                                          'text'=>'Submission text',
@@ -515,53 +595,62 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $data->reset_gradebook_grades = 1;
         $data->reset_assign_user_overrides = 1;
         $data->reset_assign_group_overrides = 1;
-        $data->courseid = $this->course->id;
-        $data->timeshift = 24*60*60;
-        $this->setUser($this->editingteachers[0]);
+        $data->courseid = $course->id;
+        $data->timeshift = DAYSECS;
+        $this->setUser($teacher);
         $assign->reset_userdata($data);
         $this->assertEquals(false, $assign->has_submissions_or_grades());
 
         // Reload the instance data.
         $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
-        $this->assertEquals($now + 24*60*60, $instance->duedate);
+        $this->assertEquals($now + DAYSECS, $instance->duedate);
 
         // Test reset using assign_reset_userdata().
         $assignduedate = $instance->duedate; // Keep old updated value for comparison.
-        $data->timeshift = 2*24*60*60;
+        $data->timeshift = (2 * DAYSECS);
         assign_reset_userdata($data);
         $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
-        $this->assertEquals($assignduedate + 2*24*60*60, $instance->duedate);
+        $this->assertEquals($assignduedate + (2 * DAYSECS), $instance->duedate);
 
         // Create one more assignment and reset, make sure time shifted for previous assignment is not changed.
-        $assign2 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
-                                               'duedate' => $now));
+        $assign2 = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'duedate' => $now,
+            ]);
         $assignduedate = $instance->duedate;
-        $data->timeshift = 3*24*60*60;
+        $data->timeshift = 3*DAYSECS;
         $assign2->reset_userdata($data);
         $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
         $this->assertEquals($assignduedate, $instance->duedate);
         $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
-        $this->assertEquals($now + 3*24*60*60, $instance2->duedate);
+        $this->assertEquals($now + 3*DAYSECS, $instance2->duedate);
 
         // Reset both assignments using assign_reset_userdata() and make sure both assignments have same date.
         $assignduedate = $instance->duedate;
         $assign2duedate = $instance2->duedate;
-        $data->timeshift = 4*24*60*60;
+        $data->timeshift = (4 * DAYSECS);
         assign_reset_userdata($data);
         $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
-        $this->assertEquals($assignduedate + 4*24*60*60, $instance->duedate);
+        $this->assertEquals($assignduedate + (4 * DAYSECS), $instance->duedate);
         $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
-        $this->assertEquals($assign2duedate + 4*24*60*60, $instance2->duedate);
+        $this->assertEquals($assign2duedate + (4 * DAYSECS), $instance2->duedate);
     }
 
     public function test_plugin_settings() {
         global $DB;
 
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
         $now = time();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
-                                               'assignsubmission_file_maxfiles'=>12,
-                                               'assignsubmission_file_maxsizebytes'=>10));
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 12,
+                'assignsubmission_file_maxsizebytes' => 10,
+            ]);
 
         $plugin = $assign->get_submission_plugin_by_type('file');
         $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
@@ -570,8 +659,13 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_update_calendar() {
         global $DB;
 
-        $this->setUser($this->editingteachers[0]);
-        $userctx = context_user::instance($this->editingteachers[0]->id)->id;
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $this->setUser($teacher);
+        $userctx = context_user::instance($teacher->id)->id;
 
         // Hack to pretend that there was an editor involved. We need both $_POST and $_REQUEST, and a sesskey.
         $draftid = file_get_unused_draft_itemid();
@@ -587,11 +681,11 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
 
         // Create a new assignment with links to a draft area.
         $now = time();
-        $assign = $this->create_instance(array(
-            'duedate' => $now,
-            'intro' => $fakearealink1,
-            'introformat' => FORMAT_HTML
-        ));
+        $assign = $this->create_instance($course, [
+                'duedate' => $now,
+                'intro' => $fakearealink1,
+                'introformat' => FORMAT_HTML
+            ]);
 
         // See if there is an event in the calendar.
         $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
@@ -611,14 +705,19 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertSame('new', $event->description);     // The pluginfile links are removed.
 
         // Create an assignment with a description that should be hidden.
-        $assign = $this->create_instance(array('duedate'=>$now + 160,
-                                               'alwaysshowdescription'=>false,
-                                               'allowsubmissionsfromdate'=>$now + 60,
-                                               'intro'=>'Some text'));
+        $assign = $this->create_instance($course, [
+                'duedate' => $now + 160,
+                'alwaysshowdescription' => false,
+                'allowsubmissionsfromdate' => $now + 60,
+                'intro' => 'Some text',
+            ]);
 
         // Get the event from the calendar.
         $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
-        $event = $DB->get_record('event', $params);
+        $event = $DB->get_record('event', [
+                'modulename' => 'assign',
+                'instance' => $assign->get_instance()->id,
+            ]);
 
         $this->assertEmpty($event->description);
 
@@ -637,8 +736,13 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_update_instance() {
         global $DB;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
 
         $now = time();
         $instance = $assign->get_instance();
@@ -648,44 +752,70 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
 
         $assign->update_instance($instance);
 
-        $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
+        $instance = $DB->get_record('assign', ['id' => $assign->get_instance()->id]);
         $this->assertEquals($now, $instance->duedate);
     }
 
     public function test_cannot_submit_empty() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('submissiondrafts'=>1));
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, ['submissiondrafts' => 1]);
 
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Test you cannot see the submit button for an offline assignment regardless.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
+    }
 
-        // Test you cannot see the submit button for an online text assignment with no submission.
-        $this->setUser($this->editingteachers[0]);
-        $instance = $assign->get_instance();
-        $instance->instance = $instance->id;
-        $instance->assignsubmission_onlinetext_enabled = 1;
+    public function test_cannot_submit_empty_no_submission() {
+        global $PAGE;
 
-        $assign->update_instance($instance);
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+            'submissiondrafts' => 1,
+            'assignsubmission_onlinetext_enabled' => 1,
+        ]);
+
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        // Test you cannot see the submit button for an online text assignment with no submission.
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
+    }
+
+    public function test_can_submit_with_submission() {
+        global $PAGE;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+            'submissiondrafts' => 1,
+            'assignsubmission_onlinetext_enabled' => 1,
+        ]);
+
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        // Add a draft.
+        $this->add_submission($student, $assign);
 
-        // Simulate a submission.
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
         // Test you can see the submit button for an online text assignment with a submission.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
     }
 
@@ -701,17 +831,23 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
      */
     public function test_new_submission_empty($data, $expected) {
         $this->resetAfterTest();
-        $assign = $this->create_instance(['assignsubmission_file_enabled' => 1,
-                                          'assignsubmission_file_maxfiles' => 12,
-                                          'assignsubmission_file_maxsizebytes' => 10,
-                                          'assignsubmission_onlinetext_enabled' => 1]);
-        $this->setUser($this->students[0]);
+
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_file_enabled' => 1,
+                'assignsubmission_file_maxfiles' => 12,
+                'assignsubmission_file_maxsizebytes' => 10,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $this->setUser($student);
         $submission = new stdClass();
 
         if ($data['file'] && isset($data['file']['filename'])) {
             $itemid = file_get_unused_draft_itemid();
             $submission->files_filemanager = $itemid;
-            $data['file'] += ['contextid' => context_user::instance($this->students[0]->id)->id, 'itemid' => $itemid];
+            $data['file'] += ['contextid' => context_user::instance($student->id)->id, 'itemid' => $itemid];
             $fs = get_file_storage();
             $fs->create_file_from_string((object)$data['file'], 'Content of ' . $data['file']['filename']);
         }
@@ -747,53 +883,99 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_list_participants() {
+        global $CFG;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        // Create 10 students.
+        for ($i = 0; $i < 10; $i++) {
+            $this->getDataGenerator()->create_and_enrol($course, 'student');
+        }
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['grade' => 100]);
+
+        $this->assertCount(10, $assign->list_participants(null, true));
+    }
+
+    public function test_list_participants_activeenrol() {
         global $CFG, $DB;
 
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('grade'=>100));
+        $this->resetAfterTest();
 
-        $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 
-        // Teacher with user preference set should see suspended users as well.
-        set_user_preference('grade_report_showonlyactiveenrol', false);
-        $assign = $this->create_instance(array('grade'=>100));
-        $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
-                count($assign->list_participants(null, true)));
+        // Create 10 students.
+        for ($i = 0; $i < 10; $i++) {
+            $this->getDataGenerator()->create_and_enrol($course, 'student');
+        }
 
-        // Non-editing teacher should not see suspended users, even if user preference is set.
-        $this->setUser($this->teachers[0]);
+        // Create 10 suspended students.
+        for ($i = 0; $i < 10; $i++) {
+            $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+        }
+
+        $this->setUser($teacher);
         set_user_preference('grade_report_showonlyactiveenrol', false);
-        $assign = $this->create_instance(array('grade'=>100));
-        $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
+        $assign = $this->create_instance($course, ['grade' => 100]);
+
+        $this->assertCount(10, $assign->list_participants(null, true));
+    }
+
+    public function test_list_participants_with_group_restriction() {
+        global $CFG;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $unrelatedstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Turn on availability and a group restriction, and check that it doesn't
-        // show users who aren't in the group.
+        // Turn on availability and a group restriction, and check that it doesn't show users who aren't in the group.
         $CFG->enableavailability = true;
-        $specialgroup = $this->getDataGenerator()->create_group(
-                array('courseid' => $this->course->id));
-        $assign = $this->create_instance(array('grade' => 100,
-                'availability' => json_encode(\core_availability\tree::get_root_json(
-                    array(\availability_group\condition::get_json($specialgroup->id))))));
-        groups_add_member($specialgroup, $this->students[0]);
-        groups_add_member($specialgroup, $this->students[1]);
+
+        $specialgroup = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $assign = $this->create_instance($course, [
+                'grade' => 100,
+                'availability' => json_encode(
+                    \core_availability\tree::get_root_json([\availability_group\condition::get_json($specialgroup->id)])
+                ),
+            ]);
+
+        groups_add_member($specialgroup, $student);
+        groups_add_member($specialgroup, $otherstudent);
         $this->assertEquals(2, count($assign->list_participants(null, true)));
     }
 
     public function test_get_participant_user_not_exist() {
-        $assign = $this->create_instance(array('grade' => 100));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+
+        $assign = $this->create_instance($course);
         $this->assertNull($assign->get_participant('-1'));
     }
 
     public function test_get_participant_not_enrolled() {
-        $assign = $this->create_instance(array('grade' => 100));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
+
         $user = $this->getDataGenerator()->create_user();
         $this->assertNull($assign->get_participant($user->id));
     }
 
     public function test_get_participant_no_submission() {
-        $assign = $this->create_instance(array('grade' => 100));
-        $student = $this->students[0];
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $participant = $assign->get_participant($student->id);
 
         $this->assertEquals($student->id, $participant->id);
@@ -803,9 +985,13 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_get_participant_granted_extension() {
-        $assign = $this->create_instance(array('grade' => 100));
-        $student = $this->students[0];
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $this->setUser($teacher);
         $assign->save_user_extension($student->id, time());
         $participant = $assign->get_participant($student->id);
 
@@ -816,26 +1002,15 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_get_participant_with_ungraded_submission() {
-        $assign = $this->create_instance(array('grade' => 100));
-        $student = $this->students[0];
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-
-        $this->setUser($student);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
         // Simulate a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-            'itemid' => file_get_unused_draft_itemid(),
-            'text' => 'Student submission text',
-            'format' => FORMAT_MOODLE
-        );
-
-        $notices = array();
-        $assign->save_submission($data, $notices);
-
-        $data = new stdClass;
-        $data->userid = $student->id;
-        $assign->submit_for_grading($data, array());
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         $participant = $assign->get_participant($student->id);
 
@@ -846,32 +1021,21 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_get_participant_with_graded_submission() {
-        $assign = $this->create_instance(array('grade' => 100));
-        $student = $this->students[0];
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-
-        $this->setUser($student);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $assign = $this->create_instance($course);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
         // Simulate a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-            'itemid' => file_get_unused_draft_itemid(),
-            'text' => 'Student submission text',
-            'format' => FORMAT_MOODLE
-        );
-
-        $notices = array();
-        $assign->save_submission($data, $notices);
-
-        $data = new stdClass;
-        $data->userid = $student->id;
-        $assign->submit_for_grading($data, array());
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
+        // TODO Find a way to kill this waitForSecond
         // This is to make sure the grade happens after the submission because
         // we have no control over the timemodified values.
         $this->waitForSecond();
-        // Grade the submission.
-        $this->setUser($this->teachers[0]);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
 
         $data = new stdClass();
         $data->grade = '50.0';
@@ -885,233 +1049,330 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertFalse($participant->grantedextension);
     }
 
-    public function test_count_teams() {
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign1 = $this->create_instance(array('teamsubmission' => 1));
-        $this->assertEquals(self::GROUP_COUNT + 1, $assign1->count_teams());
-
-        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
-        $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[0]->id, 'groupingid' => $grouping->id));
-        $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[1]->id, 'groupingid' => $grouping->id));
+    /**
+     * No active group and non-group submissions disallowed => 2 groups.
+     */
+    public function test_count_teams_no_active_non_group_allowed() {
+        $this->resetAfterTest();
 
-        // No active group and non group submissions allowed => 2 groups + the default one.
-        $params = array(
-            'teamsubmission' => 1,
-            'teamsubmissiongroupingid' => $grouping->id,
-            'preventsubmissionnotingroup' => false
-        );
-        $assign2 = $this->create_instance($params);
-        $this->assertEquals(3, $assign2->count_teams());
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // An active group => Just the selected one.
-        $this->assertEquals(1, $assign2->count_teams($this->groups[0]->id));
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group1, $student1);
+        groups_add_member($group2, $student2);
 
-        // No active group and non group submissions allowed => 2 groups + no default one.
-        $params = array('teamsubmission' => 1, 'teamsubmissiongroupingid' => $grouping->id, 'preventsubmissionnotingroup' => true);
-        $assign3 = $this->create_instance($params);
-        $this->assertEquals(2, $assign3->count_teams());
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, ['teamsubmission' => 1]);
 
-        $assign4 = $this->create_instance(array('teamsubmission' => 1, 'preventsubmissionnotingroup' => true));
-        $this->assertEquals(self::GROUP_COUNT, $assign4->count_teams());
+        $this->assertEquals(2, $assign->count_teams());
     }
 
-    public function test_submit_to_default_group() {
-        global $DB, $SESSION;
+    /**
+     * No active group and non group submissions allowed => 2 groups + the default one.
+     */
+    public function test_count_teams_non_group_allowed() {
+        $this->resetAfterTest();
 
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $student3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $this->setUser($this->editingteachers[0]);
-        $params = array('teamsubmission' => 1,
-                        'assignsubmission_onlinetext_enabled' => 1,
-                        'submissiondrafts' => 0,
-                        'groupmode' => VISIBLEGROUPS);
-        $assign = $this->create_instance($params);
-
-        $newstudent = $this->getDataGenerator()->create_user();
-        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
-        $this->getDataGenerator()->enrol_user($newstudent->id,
-                                              $this->course->id,
-                                              $studentrole->id);
-        $this->setUser($newstudent);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $notices = array();
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
 
-        $group = $assign->get_submission_group($newstudent->id);
-        $this->assertFalse($group, 'New student is in default group');
-        $assign->save_submission($data, $notices);
-        $this->assertEmpty($notices, 'No errors on save submission');
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group1->id, 'groupingid' => $grouping->id));
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group2->id, 'groupingid' => $grouping->id));
+
+        groups_add_member($group1, $student1);
+        groups_add_member($group2, $student2);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'teamsubmissiongroupingid' => $grouping->id,
+                'preventsubmissionnotingroup' => false,
+            ]);
+
+        $this->setUser($teacher);
+        $this->assertEquals(3, $assign->count_teams());
+
+        // Active group only.
+        $this->assertEquals(1, $assign->count_teams($group1->id));
+        $this->assertEquals(1, $assign->count_teams($group2->id));
+    }
+
+    /**
+     * Active group => just selected one.
+     */
+    public function test_count_teams_no_active_group() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $student3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group1->id, 'groupingid' => $grouping->id));
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group2->id, 'groupingid' => $grouping->id));
+
+        groups_add_member($group1, $student1);
+        groups_add_member($group2, $student2);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'preventsubmissionnotingroup' => true,
+            ]);
+
+        $this->setUser($teacher);
+        $this->assertEquals(2, $assign->count_teams());
+
+        // Active group only.
+        $this->assertEquals(1, $assign->count_teams($group1->id));
+        $this->assertEquals(1, $assign->count_teams($group2->id));
+    }
+
+    /**
+     * Active group => just selected one.
+     */
+    public function test_count_teams_groups_only() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'teamsubmissiongroupingid' => $grouping->id,
+                'preventsubmissionnotingroup' => false,
+            ]);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group1, $student1);
+
+        $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group2, $student2);
+
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group1->id, 'groupingid' => $grouping->id));
+        $this->getDataGenerator()->create_grouping_group(array('groupid' => $group2->id, 'groupingid' => $grouping->id));
+
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'preventsubmissionnotingroup' => true,
+            ]);
+        $this->assertEquals(2, $assign->count_teams());
+    }
+
+    public function test_submit_to_default_group() {
+        global $DB, $SESSION;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id]);
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 0,
+                'groupmode' => VISIBLEGROUPS,
+            ]);
+
+        $usergroup = $assign->get_submission_group($student->id);
+        $this->assertFalse($usergroup, 'New student is in default group');
+
+        // Add a submission.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         // Set active groups to all groups.
-        $this->setUser($this->editingteachers[0]);
-        $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
+        $this->setUser($teacher);
+        $SESSION->activegroup[$course->id]['aag'][0] = 0;
         $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
 
         // Set an active group.
-        $anothergroup = $this->groups[0];
-        $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
+        $SESSION->activegroup[$course->id]['aag'][0] = (int) $group->id;
         $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+    }
 
-        $sink->close();
+    public function test_count_submissions_no_draft() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+
+        $assign->get_user_submission($student->id, true);
+
+        // Note: Drafts count as a submission.
+        $this->assertEquals(0, $assign->count_grades());
+        $this->assertEquals(0, $assign->count_submissions());
+        $this->assertEquals(1, $assign->count_submissions(true));
+        $this->assertEquals(0, $assign->count_submissions_need_grading());
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_NEW));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_REOPENED));
+    }
+
+    public function test_count_submissions_draft() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+
+        $this->add_submission($student, $assign);
+
+        // Note: Drafts count as a submission.
+        $this->assertEquals(0, $assign->count_grades());
+        $this->assertEquals(1, $assign->count_submissions());
+        $this->assertEquals(1, $assign->count_submissions(true));
+        $this->assertEquals(0, $assign->count_submissions_need_grading());
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_NEW));
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_REOPENED));
     }
 
-    public function test_count_submissions() {
+    public function test_count_submissions_submitted() {
         global $SESSION;
 
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign1 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
+        $this->resetAfterTest();
 
-        // Simulate a submission.
-        $this->setUser($this->extrastudents[0]);
-        $submission = $assign1->get_user_submission($this->extrastudents[0]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
-        $assign1->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
-        // Leave this one as DRAFT.
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign1->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
 
-        // Simulate a submission.
-        $this->setUser($this->extrastudents[1]);
-        $submission = $assign1->get_user_submission($this->extrastudents[1]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign1->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
-        // Simulate a submission.
-        $this->setUser($this->extrastudents[2]);
-        $submission = $assign1->get_user_submission($this->extrastudents[2]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign1->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $this->assertEquals(0, $assign->count_grades());
+        $this->assertEquals(1, $assign->count_submissions());
+        $this->assertEquals(1, $assign->count_submissions(true));
+        $this->assertEquals(1, $assign->count_submissions_need_grading());
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_NEW));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_REOPENED));
+    }
 
-        // Simulate a submission.
-        $this->setUser($this->extrastudents[3]);
-        $submission = $assign1->get_user_submission($this->extrastudents[3]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign1->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+    public function test_count_submissions_graded() {
+        $this->resetAfterTest();
 
-        // Simulate a submission for suspended user, this will never be counted.
-        $this->setUser($this->extrastudents[3]);
-        $submission = $assign1->get_user_submission($this->extrasuspendedstudents[0]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign1->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Wait 1 second so the submission and grade do not have the same timemodified.
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
         $this->waitForSecond();
-        // Simulate adding a grade.
-        $this->setUser($this->editingteachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign1->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
-        $assign1->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
 
-        // Create a new submission with status NEW.
-        $this->setUser($this->extrastudents[4]);
-        $submission = $assign1->get_user_submission($this->extrastudents[4]->id, true);
+        // Although it has been graded, it is still marked as submitted.
+        $this->assertEquals(1, $assign->count_grades());
+        $this->assertEquals(1, $assign->count_submissions());
+        $this->assertEquals(1, $assign->count_submissions(true));
+        $this->assertEquals(0, $assign->count_submissions_need_grading());
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_NEW));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_REOPENED));
+    }
 
-        $this->assertEquals(2, $assign1->count_grades());
-        $this->assertEquals(4, $assign1->count_submissions());
-        $this->assertEquals(5, $assign1->count_submissions(true));
-        $this->assertEquals(2, $assign1->count_submissions_need_grading());
-        $this->assertEquals(3, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
-        $this->assertEquals(1, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
+    public function test_count_submissions_graded_group() {
+        global $SESSION;
 
-        // Groups.
-        $assign2 = $this->create_instance(array(
-            'assignsubmission_onlinetext_enabled' => 1,
-            'groupmode' => VISIBLEGROUPS
-        ));
+        $this->resetAfterTest();
 
-        $this->setUser($this->extrastudents[1]);
-        $submission = $assign2->get_user_submission($this->extrastudents[1]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign2->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
-                                         'text' => 'Submission text',
-                                         'format' => FORMAT_MOODLE);
-        $plugin = $assign2->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $othergroup = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group, $student);
 
-        $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'groupmode' => VISIBLEGROUPS,
+            ]);
+
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+
+        // The user should still be listed when fetching all groups.
+        $this->setUser($teacher);
+        $SESSION->activegroup[$course->id]['aag'][0] = 0;
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+
+        // The user should still be listed when fetching just their group.
+        $SESSION->activegroup[$course->id]['aag'][0] = $group->id;
+        $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+
+        // The user should still be listed when fetching just their group.
+        $SESSION->activegroup[$course->id]['aag'][0] = $othergroup->id;
+        $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
+    }
+
+    // TODO
+    public function x_test_count_submissions_for_team() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $othergroup = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group, $student);
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'teamsubmission' => 1,
+            ]);
+
+        // Add a graded submission.
+        $this->add_submission($student, $assign);
 
-        // Set active groups to all groups.
-        $this->setUser($this->editingteachers[0]);
-        $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
-        $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
-
-        // Set the user group.
-        $studentgroups = groups_get_user_groups($this->course->id, $this->extrastudents[1]->id);
-        $this->assertEquals(1, count($studentgroups));
-        $studentgroup = array_pop($studentgroups);
-        $SESSION->activegroup[$this->course->id]['aag'][0] = $studentgroup[0];
-        $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
-
-        // Set another group.
-        $anothergroup = $this->groups[0];
-        $this->assertNotEquals($anothergroup->id, $studentgroup[0]);
-        $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
-        $this->assertEquals(0, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
-    }
-
-    public function test_count_submissions_for_groups() {
-        $this->create_extra_users();
-        $groupid = null;
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1, 'teamsubmission' => 1));
 
-        // Simulate a submission.
-        $this->setUser($this->extrastudents[0]);
-        $submission = $assign->get_group_submission($this->extrastudents[0]->id, $groupid, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
-        // Leave this one as DRAFT.
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
-                                         'text' => 'Submission text',
-                                         'format' => FORMAT_MOODLE);
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
 
         // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $data = new stdClass();
         $data->grade = '50.0';
         $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
@@ -1153,7 +1414,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $plugin->save($submission, $data);
 
         // Simulate adding a grade.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $data = new stdClass();
         $data->grade = '50.0';
         $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
@@ -1170,130 +1431,224 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
     }
 
-    public function test_get_grading_userid_list() {
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+    public function test_get_grading_userid_list_only_active() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $suspendedstudent = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+
+        $this->setUser($teacher);
+
+        $assign = $this->create_instance($course);
+        $this->assertCount(1, $assign->testable_get_grading_userid_list());
+    }
+
+    public function test_get_grading_userid_list_all() {
+        $this->resetAfterTest();
 
-        $users = $assign->testable_get_grading_userid_list();
-        $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $suspendedstudent = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         set_user_preference('grade_report_showonlyactiveenrol', false);
-        $assign = $this->create_instance();
 
-        $users = $assign->testable_get_grading_userid_list();
-        $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
+        $assign = $this->create_instance($course);
+        $this->assertCount(2, $assign->testable_get_grading_userid_list());
     }
 
     public function test_cron() {
+        $this->resetAfterTest();
+
         // First run cron so there are no messages waiting to be sent (from other tests).
         cron_setup_user();
         assign::cron();
 
-        // Now create an assignment and add some feedback.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('sendstudentnotifications'=>1));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
-        $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
+        // Now create an assignment and add some feedback.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'sendstudentnotifications' => 1,
+            ]);
 
-        $data->sendstudentnotifications = false;
-        $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
 
-        // Now run cron and see that one message was sent.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
+        $this->expectOutputRegex('/Done processing 1 assignment submissions/');
         cron_setup_user();
-        $this->expectOutputRegex('/Done processing 2 assignment submissions/');
+        $sink = $this->redirectMessages();
         assign::cron();
-
         $messages = $sink->get_messages();
-        // The sent count should be 2, because the 3rd one was marked as do not send notifications.
-        $this->assertEquals(2, count($messages));
+
+        $this->assertEquals(1, count($messages));
         $this->assertEquals(1, $messages[0]->notification);
         $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
+    }
 
-        // Regrading a grade causes a notification to the user.
-        $data->sendstudentnotifications = true;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+    public function test_cron_without_notifications() {
+        $this->resetAfterTest();
+
+        // First run cron so there are no messages waiting to be sent (from other tests).
+        cron_setup_user();
+        assign::cron();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        // Now create an assignment and add some feedback.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'sendstudentnotifications' => 1,
+            ]);
+
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0, [
+                'sendstudentnotifications' => 0,
+            ]);
+
+        cron_setup_user();
+        $sink = $this->redirectMessages();
         assign::cron();
         $messages = $sink->get_messages();
-        $this->assertEquals(3, count($messages));
+
+        $this->assertEquals(0, count($messages));
+    }
+
+    public function test_cron_regraded() {
+        $this->resetAfterTest();
+
+        // First run cron so there are no messages waiting to be sent (from other tests).
+        cron_setup_user();
+        assign::cron();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        // Now create an assignment and add some feedback.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'sendstudentnotifications' => 1,
+            ]);
+
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
+
+        $this->expectOutputRegex('/Done processing 1 assignment submissions/');
+        cron_setup_user();
+        assign::cron();
+
+        // Regrade.
+        $this->mark_submission($teacher, $assign, $student, 50.0);
+
+        $this->expectOutputRegex('/Done processing 1 assignment submissions/');
+        cron_setup_user();
+        $sink = $this->redirectMessages();
+        assign::cron();
+        $messages = $sink->get_messages();
+
+        $this->assertEquals(1, count($messages));
+        $this->assertEquals(1, $messages[0]->notification);
+        $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
     }
 
     /**
      * Test delivery of grade notifications as controlled by marking workflow.
      */
     public function test_markingworkflow_cron() {
+        $this->resetAfterTest();
+
         // First run cron so there are no messages waiting to be sent (from other tests).
         cron_setup_user();
         assign::cron();
 
-        // Now create an assignment with marking workflow enabled.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('sendstudentnotifications' => 1, 'markingworkflow' => 1));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
+        // Now create an assignment and add some feedback.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'sendstudentnotifications' => 1,
+                'markingworkflow' => 1,
+            ]);
+
+        // Mark a submission but set the workflowstate to an unreleased state.
+        // This should not trigger a notification.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0, [
+                'sendstudentnotifications' => 1,
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE,
+            ]);
+
+        cron_setup_user();
+        $sink = $this->redirectMessages();
+        assign::cron();
+        $messages = $sink->get_messages();
 
-        // This student will not receive notification.
-        $data->sendstudentnotifications = 1;
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->assertEquals(0, count($messages));
 
-        // This student will receive notification.
-        $data->sendstudentnotifications = 1;
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
-        $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
+        // Transition to the released state.
+        $this->setUser($teacher);
+        $submission = $assign->get_user_submission($student->id, true);
+        $submission->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
+        $assign->testable_apply_grade_to_user($submission, $student->id, 0);
 
         // Now run cron and see that one message was sent.
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
         cron_setup_user();
+        $sink = $this->redirectMessages();
         $this->expectOutputRegex('/Done processing 1 assignment submissions/');
         assign::cron();
-
         $messages = $sink->get_messages();
+
         $this->assertEquals(1, count($messages));
-        $this->assertEquals($messages[0]->useridto, $this->students[1]->id);
+        $this->assertEquals(1, $messages[0]->notification);
         $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
     }
 
     public function test_cron_message_includes_courseid() {
+        $this->resetAfterTest();
+
         // First run cron so there are no messages waiting to be sent (from other tests).
         cron_setup_user();
         assign::cron();
 
-        // Now create an assignment.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('sendstudentnotifications' => 1));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        // Now create an assignment and add some feedback.
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'sendstudentnotifications' => 1,
+            ]);
 
+        // Mark a submission but set the workflowstate to an unreleased state.
+        // This should not trigger a notification.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student);
+        phpunit_util::stop_message_redirection();
+
+        // Now run cron and see that one message was sent.
+        cron_setup_user();
         $this->preventResetByRollback();
         $sink = $this->redirectEvents();
         $this->expectOutputRegex('/Done processing 1 assignment submissions/');
-
         assign::cron();
 
         $events = $sink->get_events();
-        // Two notifications are sent, one to student and one to teacher. This generates
-        // four events:
-        // core\event\notification_sent
-        // core\event\notification_viewed
-        // core\event\notification_sent
-        // core\event\notification_viewed.
         $event = reset($events);
         $this->assertInstanceOf('\core\event\notification_sent', $event);
         $this->assertEquals($assign->get_course()->id, $event->other['courseid']);
@@ -1301,34 +1656,44 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     }
 
     public function test_is_graded() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
 
-        // Simulate adding a grade.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
 
-        $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
-        $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, 50.0);
+
+        $this->setUser($teacher);
+        $this->assertEquals(true, $assign->testable_is_graded($student->id));
+        $this->assertEquals(false, $assign->testable_is_graded($otherstudent->id));
     }
 
     public function test_can_grade() {
         global $DB;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
 
-        $this->setUser($this->students[0]);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
+
+        $this->setUser($student);
         $this->assertEquals(false, $assign->can_grade());
-        $this->setUser($this->editingteachers[0]);
-        $this->assertEquals(true, $assign->can_grade());
-        $this->setUser($this->teachers[0]);
+
+        $this->setUser($teacher);
         $this->assertEquals(true, $assign->can_grade());
 
         // Test the viewgrades capability - without mod/assign:grade.
-        $this->setUser($this->students[0]);
+        $this->setUser($student);
+
         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
         assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
         $this->assertEquals(false, $assign->can_grade());
@@ -1337,399 +1702,541 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_can_view_submission() {
         global $DB;
 
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-
-        $this->setUser($this->students[0]);
-        $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
-        $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
-        $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
-        $this->setUser($this->teachers[0]);
-        $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
-        $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
-        $this->setUser($this->editingteachers[0]);
-        $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $suspendedstudent = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+
+        $assign = $this->create_instance($course);
+
+        $this->setUser($student);
+        $this->assertEquals(true, $assign->can_view_submission($student->id));
+        $this->assertEquals(false, $assign->can_view_submission($otherstudent->id));
+        $this->assertEquals(false, $assign->can_view_submission($teacher->id));
+
+        $this->setUser($teacher);
+        $this->assertEquals(true, $assign->can_view_submission($student->id));
+        $this->assertEquals(true, $assign->can_view_submission($otherstudent->id));
+        $this->assertEquals(true, $assign->can_view_submission($teacher->id));
+        $this->assertEquals(false, $assign->can_view_submission($suspendedstudent->id));
+
+        $this->setUser($editingteacher);
+        $this->assertEquals(true, $assign->can_view_submission($student->id));
+        $this->assertEquals(true, $assign->can_view_submission($otherstudent->id));
+        $this->assertEquals(true, $assign->can_view_submission($teacher->id));
+        $this->assertEquals(true, $assign->can_view_submission($suspendedstudent->id));
 
         // Test the viewgrades capability - without mod/assign:grade.
-        $this->setUser($this->students[0]);
+        $this->setUser($student);
         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
         assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
-        $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
-        $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
-        $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
+        $this->assertEquals(true, $assign->can_view_submission($student->id));
+        $this->assertEquals(true, $assign->can_view_submission($otherstudent->id));
+        $this->assertEquals(true, $assign->can_view_submission($teacher->id));
+        $this->assertEquals(false, $assign->can_view_submission($suspendedstudent->id));
     }
 
-
     public function test_update_submission() {
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
 
-        $this->setUser($this->extrastudents[0]);
-        $now = time();
-        $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
+
+        $this->add_submission($student, $assign);
+        $submission = $assign->get_user_submission($student->id, 0);
+        $assign->testable_update_submission($submission, $student->id, true, true);
+
+        $this->setUser($teacher);
 
-        $this->setUser($this->teachers[0]);
         // Verify the gradebook update.
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[0]->id);
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $student->id);
 
-        $this->assertEquals($this->extrastudents[0]->id,
-                            $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$student->id]));
+        $this->assertEquals($student->id, $gradinginfo->items[0]->grades[$student->id]->usermodified);
+    }
 
-        // Now verify group assignments.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('teamsubmission'=>1));
+    public function test_update_submission_team() {
+        $this->resetAfterTest();
 
-        $this->setUser($this->extrastudents[0]);
-        $now = time();
-        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
-
-        // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
-
-        $this->setUser($this->editingteachers[0]);
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[0]->id);
-
-        $this->assertEquals($this->extrastudents[0]->id,
-                            $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
-
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[self::GROUP_COUNT]->id);
-
-        $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
-                            $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
-
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrasuspendedstudents[0]->id);
-        $this->assertEquals($this->extrasuspendedstudents[0]->id,
-                            $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
-
-        // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('teamsubmission'=>1));
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
 
-        $this->setUser($this->extrastudents[1]);
-        $now = time();
-        $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
-        $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
-
-        $this->setUser($this->teachers[0]);
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[1]->id);
-
-        $this->assertEquals($this->extrastudents[1]->id,
-                            $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
-
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[self::GROUP_COUNT+1]->id);
-
-        $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
-                            $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
-
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrasuspendedstudents[1]->id);
-        $this->assertEquals($this->extrasuspendedstudents[1]->id,
-                            $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
-
-        // Now verify blind marking.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('blindmarking'=>1));
-
-        $this->setUser($this->extrastudents[0]);
-        $now = time();
-        $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $otherstudent);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+            ]);
+
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $student->id);
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$student->id]));
+        $this->assertNull($gradinginfo->items[0]->grades[$student->id]->usermodified);
+
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $otherstudent->id);
+        $this->asserttrue(isset($gradinginfo->items[0]->grades[$otherstudent->id]));
+        $this->assertNull($gradinginfo->items[0]->grades[$otherstudent->id]->usermodified);
 
-        $this->setUser($this->editingteachers[0]);
-        $gradinginfo = grade_get_grades($this->course->id,
-                                        'mod',
-                                        'assign',
-                                        $assign->get_instance()->id,
-                                        $this->extrastudents[0]->id);
+        $this->add_submission($student, $assign);
+        $submission = $assign->get_group_submission($student->id, 0, true);
+        $assign->testable_update_submission($submission, $student->id, true, true);
 
-        $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
+        // Verify the gradebook update for the student.
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $student->id);
+
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$student->id]));
+        $this->assertEquals($student->id, $gradinginfo->items[0]->grades[$student->id]->usermodified);
+
+        // Verify the gradebook update for the other student.
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $otherstudent->id);
+
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$otherstudent->id]));
+        $this->assertEquals($otherstudent->id, $gradinginfo->items[0]->grades[$otherstudent->id]->usermodified);
+    }
+
+    public function test_update_submission_suspended() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+
+        $assign = $this->create_instance($course);
+
+        $this->add_submission($student, $assign);
+        $submission = $assign->get_user_submission($student->id, 0);
+        $assign->testable_update_submission($submission, $student->id, true, false);
+
+        $this->setUser($teacher);
+
+        // Verify the gradebook update.
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $student->id);
+
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$student->id]));
+        $this->assertEquals($student->id, $gradinginfo->items[0]->grades[$student->id]->usermodified);
+    }
+
+    public function test_update_submission_blind() {
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'blindmarking' => 1,
+            ]);
+
+        $this->add_submission($student, $assign);
+        $submission = $assign->get_user_submission($student->id, 0);
+        $assign->testable_update_submission($submission, $student->id, true, false);
+
+        // Verify the gradebook update.
+        $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $assign->get_instance()->id, $student->id);
+
+        // The usermodified is not set because this is blind marked.
+        $this->assertTrue(isset($gradinginfo->items[0]->grades[$student->id]));
+        $this->assertNull($gradinginfo->items[0]->grades[$student->id]->usermodified);
     }
 
     public function test_group_submissions_submit_for_marking_requireallteammemberssubmit() {
         global $PAGE;
 
-        $this->create_extra_users();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $otherstudent);
+
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+                'requireallteammemberssubmit' => 1,
+            ]);
+
         // Now verify group assignments.
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('teamsubmission'=>1,
-                                               'assignsubmission_onlinetext_enabled'=>1,
-                                               'submissiondrafts'=>1,
-                                               'requireallteammemberssubmit'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $this->setUser($teacher);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Add a submission.
-        $this->setUser($this->extrastudents[0]);
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
-
-        $notices = array();
-        $assign->save_submission($data, $notices);
+        $this->add_submission($student, $assign);
 
         // Check we can see the submit button.
-        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertContains(get_string('submitassignment', 'assign'), $output);
 
-        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
+        $submission = $assign->get_group_submission($student->id, 0, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
+        $assign->testable_update_submission($submission, $student->id, true, true);
 
         // Check that the student does not see "Submit" button.
-        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
 
         // Change to another user in the same group.
-        $this->setUser($this->extrastudents[self::GROUP_COUNT]);
-        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $this->setUser($otherstudent);
+        $output = $assign->view_student_summary($otherstudent, true);
         $this->assertContains(get_string('submitassignment', 'assign'), $output);
 
-        $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
+        $submission = $assign->get_group_submission($otherstudent->id, 0, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
-        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $assign->testable_update_submission($submission, $otherstudent->id, true, true);
+        $output = $assign->view_student_summary($otherstudent, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
     }
 
     public function test_group_submissions_submit_for_marking() {
         global $PAGE;
 
-        $this->create_extra_users();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group, $otherstudent);
+
         // Now verify group assignments.
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
         $time = time();
-        $assign = $this->create_instance(array('teamsubmission'=>1,
-                                               'assignsubmission_onlinetext_enabled'=>1,
-                                               'submissiondrafts'=>1,
-                                               'requireallteammemberssubmit'=>0,
-                                               'duedate' => $time - 2*24*60*60));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
-
-        $this->setUser($this->extrastudents[0]);
+        $assign = $this->create_instance($course, [
+                'teamsubmission' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+                'requireallteammemberssubmit' => 0,
+                'duedate' => $time - (2 * DAYSECS),
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
         // Add a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Submission text',
-                                         'format'=>FORMAT_MOODLE);
+        $this->add_submission($student, $assign);
 
-        $notices = array();
-        $assign->save_submission($data, $notices);
 
         // Check we can see the submit button.
-        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertContains(get_string('submitassignment', 'assign'), $output);
         $this->assertContains(get_string('timeremaining', 'assign'), $output);
         $difftime = time() - $time;
-        $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time((2 * DAYSECS) + $difftime)), $output);
 
-        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
+        $submission = $assign->get_group_submission($student->id, 0, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
+        $assign->testable_update_submission($submission, $student->id, true, true);
 
         // Check that the student does not see "Submit" button.
-        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
 
         // Change to another user in the same group.
-        $this->setUser($this->extrastudents[self::GROUP_COUNT]);
-        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $this->setUser($otherstudent);
+        $output = $assign->view_student_summary($otherstudent, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
 
         // Check that time remaining is not overdue.
         $this->assertContains(get_string('timeremaining', 'assign'), $output);
         $difftime = time() - $time;
-        $this->assertContains(get_string('submittedlate', 'assign', format_time(2*24*60*60 + $difftime)), $output);
+        $this->assertContains(get_string('submittedlate', 'assign', format_time((2 * DAYSECS) + $difftime)), $output);
 
-        $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
+        $submission = $assign->get_group_submission($otherstudent->id, 0, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
-        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $assign->testable_update_submission($submission, $otherstudent->id, true, true);
+        $output = $assign->view_student_summary($otherstudent, true);
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
     }
 
     public function test_submissions_open() {
-        $this->setUser($this->editingteachers[0]);
+        global $DB;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $suspendedstudent = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+
+        $this->setAdminUser();
 
         $now = time();
-        $tomorrow = $now + 24*60*60;
-        $oneweek = $now + 7*24*60*60;
-        $yesterday = $now - 24*60*60;
+        $tomorrow = $now + DAYSECS;
+        $oneweek = $now + WEEKSECS;
+        $yesterday = $now - DAYSECS;
 
-        $assign = $this->create_instance();
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $assign = $this->create_instance(array('duedate'=>$tomorrow));
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course, ['duedate' => $tomorrow]);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $assign = $this->create_instance(array('duedate'=>$yesterday));
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course, ['duedate' => $yesterday]);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course, ['duedate' => $yesterday, 'cutoffdate' => $tomorrow]);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
-        $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course, ['duedate' => $yesterday, 'cutoffdate' => $yesterday]);
+        $this->assertEquals(false, $assign->testable_submissions_open($student->id));
 
-        $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign->testable_save_user_extension($student->id, $tomorrow);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $assign = $this->create_instance(array('submissiondrafts'=>1));
-        $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
+        $assign = $this->create_instance($course, ['submissiondrafts' => 1]);
+        $this->assertEquals(true, $assign->testable_submissions_open($student->id));
 
-        $this->setUser($this->students[0]);
-        $now = time();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $this->setUser($student);
+        $submission = $assign->get_user_submission($student->id, true);
         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-        $this->setUser($this->editingteachers[0]);
-        $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
+        $assign->testable_update_submission($submission, $student->id, true,&nb