MDL-55609 mod_assign: Remove shared setUp for all tests
authorAndrew Nicols <andrew@nicols.co.uk>
Fri, 25 May 2018 03:40:59 +0000 (11:40 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Thu, 31 May 2018 23:30:32 +0000 (07:30 +0800)
mod/assign/tests/events_test.php
mod/assign/tests/externallib_test.php
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/search_test.php
mod/assign/tests/upgradelib_test.php

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..fb336e6 100644 (file)
@@ -19,6 +19,7 @@ defined('MOODLE_INTERNAL') || die();
 global $CFG;
 
 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/mod/assign/externallib.php');
 
 /**
  * External mod assign functions unit tests
@@ -30,14 +31,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
      */
diff --git a/mod/assign/tests/generator.php b/mod/assign/tests/generator.php
new file mode 100644 (file)
index 0000000..96ea18c
--- /dev/null
@@ -0,0 +1,131 @@
+<?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($CFG->dirroot . '/mod/assign/upgradelib.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..4a6dae9 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->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($returnparams, $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, false);
+
+        $this->setUser($teacher);
+        $this->assertEquals(false, $assign->testable_submissions_open($student->id));
     }
 
     public function test_get_graders() {
-        $this->create_extra_users();
-        $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');
+
+        $this->setAdminUser();
 
         // Create an assignment with no groups.
-        $assign = $this->create_instance();
-        $this->assertCount(self::DEFAULT_TEACHER_COUNT +
-                           self::DEFAULT_EDITING_TEACHER_COUNT +
-                           self::EXTRA_TEACHER_COUNT +
-                           self::EXTRA_EDITING_TEACHER_COUNT,
-                           $assign->testable_get_graders($this->students[0]->id));
+        $assign = $this->create_instance($course);
+        $this->assertCount(2, $assign->testable_get_graders($student->id));
+    }
+
+    public function test_get_graders_separate_groups() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_add_member($group1, $student);
+
+        $this->setAdminUser();
 
         // Force create an assignment with SEPARATEGROUPS.
-        $data = new stdClass();
-        $data->courseid = $this->course->id;
-        $data->name = 'Grouping';
-        $groupingid = groups_create_grouping($data);
-        groups_assign_grouping($groupingid, $this->groups[0]->id);
-        $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
-
-        $this->setUser($this->students[1]);
-        $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
+        $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+
+        $assign = $this->create_instance($course, [
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
+
+        $this->assertCount(4, $assign->testable_get_graders($student->id));
+
         // Note the second student is in a group that is not in the grouping.
         // This means that we get all graders that are not in a group in the grouping.
-        $this->assertCount(10, $assign->testable_get_graders($this->students[1]->id));
+        $this->assertCount(4, $assign->testable_get_graders($otherstudent->id));
     }
 
     public function test_get_notified_users() {
         global $CFG, $DB;
 
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $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));
+
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        groups_add_member($group1, $teacher);
+
+        $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        groups_add_member($group1, $editingteacher);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
         $capability = 'mod/assign:receivegradernotifications';
-        $coursecontext = context_course::instance($this->course->id);
+        $coursecontext = context_course::instance($course->id);
         $role = $DB->get_record('role', array('shortname' => 'teacher'));
 
-        $this->create_extra_users();
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
 
         // Create an assignment with no groups.
-        $assign = $this->create_instance();
+        $assign = $this->create_instance($course);
 
-        $this->assertCount(self::DEFAULT_TEACHER_COUNT +
-                           self::DEFAULT_EDITING_TEACHER_COUNT +
-                           self::EXTRA_TEACHER_COUNT +
-                           self::EXTRA_EDITING_TEACHER_COUNT,
-                           $assign->testable_get_notifiable_users($this->students[0]->id));
+        $this->assertCount(3, $assign->testable_get_notifiable_users($student->id));
 
         // Change nonediting teachers role to not receive grader notifications.
         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
 
-        $this->assertCount(self::DEFAULT_EDITING_TEACHER_COUNT +
-                           self::EXTRA_EDITING_TEACHER_COUNT,
-                           $assign->testable_get_notifiable_users($this->students[0]->id));
+        // Only the editing teachers will be returned.
+        $this->assertCount(1, $assign->testable_get_notifiable_users($student->id));
+
+        // Note the second student is in a group that is not in the grouping.
+        // This means that we get all graders that are not in a group in the grouping.
+        $this->assertCount(1, $assign->testable_get_notifiable_users($otherstudent->id));
+    }
+
+    public function test_get_notified_users_in_grouping() {
+        global $CFG, $DB;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $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));
+
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        groups_add_member($group1, $teacher);
+
+        $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        groups_add_member($group1, $editingteacher);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        // Force create an assignment with SEPARATEGROUPS.
+        $assign = $this->create_instance($course, [
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
 
-        // Reset nonediting teachers role to default.
-        unassign_capability($capability, $role->id, $coursecontext);
+        // Student is in a group - only the tacher and editing teacher in the group shoudl be present.
+        $this->setUser($student);
+        $this->assertCount(2, $assign->testable_get_notifiable_users($student->id));
 
-        // Force create an assignment with SEPARATEGROUPS.
-        $data = new stdClass();
-        $data->courseid = $this->course->id;
-        $data->name = 'Grouping';
-        $groupingid = groups_create_grouping($data);
-        groups_assign_grouping($groupingid, $this->groups[0]->id);
-        $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
-
-        $this->setUser($this->students[1]);
-        $this->assertCount(4, $assign->testable_get_notifiable_users($this->students[0]->id));
         // Note the second student is in a group that is not in the grouping.
         // This means that we get all graders that are not in a group in the grouping.
-        $this->assertCount(10, $assign->testable_get_notifiable_users($this->students[1]->id));
+        $this->assertCount(1, $assign->testable_get_notifiable_users($otherstudent->id));
 
         // Change nonediting teachers role to not receive grader notifications.
+        $capability = 'mod/assign:receivegradernotifications';
+        $coursecontext = context_course::instance($course->id);
+        $role = $DB->get_record('role', ['shortname' => 'teacher']);
         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
 
-        $this->assertCount(2, $assign->testable_get_notifiable_users($this->students[0]->id));
+        // Only the editing teachers will be returned.
+        $this->assertCount(1, $assign->testable_get_notifiable_users($student->id));
+
         // Note the second student is in a group that is not in the grouping.
         // This means that we get all graders that are not in a group in the grouping.
-        $this->assertCount(5, $assign->testable_get_notifiable_users($this->students[1]->id));
+        // Unfortunately there are no editing teachers who are not in a group.
+        $this->assertCount(0, $assign->testable_get_notifiable_users($otherstudent->id));
     }
 
     public function test_group_members_only() {
         global $CFG;
 
-        $this->setAdminUser();
-        $this->create_extra_users();
-        $CFG->enableavailability = true;
-        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
-        groups_assign_grouping($grouping->id, $this->groups[0]->id);
+        $this->resetAfterTest();
 
-        // Force create an assignment with SEPARATEGROUPS.
-        $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
-                array('availability' => json_encode(\core_availability\tree::get_root_json(array(
-                    \availability_grouping\condition::get_json()))),
-                'groupingid' => $grouping->id));
+        $course = $this->getDataGenerator()->create_course();
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $this->getDataGenerator()->create_grouping_group([
+                'groupid' => $group1->id,
+                'groupingid' => $grouping->id,
+            ]);
 
-        $cm = get_coursemodule_from_instance('assign', $instance->id);
-        $context = context_module::instance($cm->id);
-        $assign = new testable_assign($context, $cm, $this->course);
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        $this->getDataGenerator()->create_grouping_group([
+                'groupid' => $group2->id,
+                'groupingid' => $grouping->id,
+            ]);
+
+        $group3 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+
+        // Add users in the following groups
+        // - Teacher - Group 1.
+        // - Student - Group 1.
+        // - Student - Group 2.
+        // - Student - Unrelated Group
+        // - Student - No group.
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        groups_add_member($group1, $teacher);
+
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student);
+
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group2, $otherstudent);
+
+        $yetotherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group2, $otherstudent);
 
-        $this->setUser($this->teachers[0]);
-        get_fast_modinfo($this->course, 0, true);
-        $this->assertCount(5, $assign->list_participants(0, true));
+        $this->getDataGenerator()->create_and_enrol($course, 'student');
 
+        $this->setAdminUser();
+
+        $CFG->enableavailability = true;
+        $assign = $this->create_instance($course, [], [
+                'availability' => json_encode(
+                    \core_availability\tree::get_root_json([\availability_grouping\condition::get_json()])
+                ),
+                'groupingid' => $grouping->id,
+            ]);
+
+        // The two students in groups should be returned, but not the teacher in the group, or the student not in the
+        // group, or the student in an unrelated group.
+        $this->setUser($teacher);
+        $participants = $assign->list_participants(0, true);
+        $this->assertCount(2, $participants);
+        $this->assertTrue(isset($participants[$student->id]));
+        $this->assertTrue(isset($participants[$otherstudent->id]));
     }
 
     public function test_get_uniqueid_for_user() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $students = [];
+        for ($i = 0; $i < 10; $i++) {
+            $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+            $students[$student->id] = $student;
+        }
+
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course);
 
-        foreach ($this->students as $student) {
+        foreach ($students as $student) {
             $uniqueid = $assign->get_uniqueid_for_user($student->id);
             $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
         }
@@ -1738,128 +2245,165 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_show_student_summary() {
         global $CFG, $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $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);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // No feedback should be available because this student has not been graded.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
-        $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotRegexp('/Feedback/', $output, 'Do not show feedback if there is no grade');
+
         // 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);
 
         // Now we should see the feedback.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
-        $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertRegexp('/Feedback/', $output, 'Show feedback if there is a grade');
 
         // Now hide the grade in gradebook.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         require_once($CFG->libdir.'/gradelib.php');
         $gradeitem = new grade_item(array(
             'itemtype'      => 'mod',
             'itemmodule'    => 'assign',
             'iteminstance'  => $assign->get_instance()->id,
-            'courseid'      => $this->course->id));
+            'courseid'      => $course->id));
 
         $gradeitem->set_hidden(1, false);
 
         // No feedback should be available because the grade is hidden.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
-        $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotRegexp('/Feedback/', $output, 'Do not show feedback if the grade is hidden in the gradebook');
+    }
 
-        // Do the same but add feedback.
-        $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
+    public function test_show_student_summary_with_feedback() {
+        global $CFG, $PAGE;
 
-        $this->setUser($this->teachers[0]);
-        $grade = $assign->get_user_grade($this->students[0]->id, true);
-        $data = new stdClass();
-        $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
-                                         'format'=>FORMAT_MOODLE);
-        $plugin = $assign->get_feedback_plugin_by_type('comments');
-        $plugin->save($grade, $data);
+        $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, [
+                'assignfeedback_comments_enabled' => 1
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        // No feedback should be available because this student has not been graded.
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotRegexp('/Feedback/', $output);
+
+        // Simulate adding a grade.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
+        $this->mark_submission($teacher, $assign, $student, null, [
+                'assignfeedbackcomments_editor' => [
+                    'text' => 'Tomato sauce',
+                    'format' => FORMAT_MOODLE,
+                ],
+            ]);
+
+        // Should have feedback but no grade.
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertRegexp('/Feedback/', $output);
+        $this->assertRegexp('/Tomato sauce/', $output);
+        $this->assertNotRegexp('/Grade/', $output, 'Do not show grade when there is no grade.');
+        $this->assertNotRegexp('/Graded on/', $output, 'Do not show graded date when there is no grade.');
+
+        // Add a grade now.
+        $this->mark_submission($teacher, $assign, $student, 50.0, [
+                'assignfeedbackcomments_editor' => [
+                    'text' => 'Bechamel sauce',
+                    'format' => FORMAT_MOODLE,
+                ],
+            ]);
 
         // Should have feedback but no grade.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
-        $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
-        $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
-        $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotRegexp('/Tomato sauce/', $output);
+        $this->assertRegexp('/Bechamel sauce/', $output);
+        $this->assertRegexp('/Grade/', $output);
+        $this->assertRegexp('/Graded on/', $output);
 
         // Now hide the grade in gradebook.
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         $gradeitem = new grade_item(array(
             'itemtype'      => 'mod',
             'itemmodule'    => 'assign',
             'iteminstance'  => $assign->get_instance()->id,
-            'courseid'      => $this->course->id));
+            'courseid'      => $course->id));
 
         $gradeitem->set_hidden(1, false);
 
         // No feedback should be available because the grade is hidden.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
-        $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotRegexp('/Feedback/', $output, 'Do not show feedback if the grade is hidden in the gradebook');
     }
 
+    /**
+     * Test reopen behavior when in "Manual" mode.
+     */
     public function test_attempt_reopen_method_manual() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
-                                               'maxattempts'=>3,
-                                               'submissiondrafts'=>1,
-                                               'assignsubmission_onlinetext_enabled'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
+                'maxattempts' => 3,
+                'submissiondrafts' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Student should be able to see an add submission button.
-        $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->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
 
         // Add a submission.
-        $now = time();
-        $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);
-
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         // Verify the student cannot make changes to the submission.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
 
         // 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->mark_submission($teacher, $assign, $student);
 
         // Check the student can see the grade.
-        $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->assertNotEquals(false, strpos($output, '50.0'));
 
         // 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);
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+        $result = $assign->testable_process_add_attempt($student->id);
         $this->assertEquals(true, $result);
 
         // Check that the previous attempt is now in the submission history table.
-        $this->setUser($this->students[0]);
-        $output = $assign->view_student_summary($this->students[0], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         // Need a better check.
         $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
 
@@ -1871,12 +2415,12 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         // Check that the student now has a submission history.
         $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
 
-        $this->setUser($this->teachers[0]);
+        $this->setUser($teacher);
         // Check that the grading table loads correctly and contains this user.
         // This is also testing that we do not get duplicate rows in the grading table.
         $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
         $output = $assign->get_renderer()->render($gradingtable);
-        $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
+        $this->assertEquals(true, strpos($output, $student->lastname));
 
         // Should be 1 not 2.
         $this->assertEquals(1, $assign->count_submissions());
@@ -1891,22 +2435,20 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $assign->update_instance($formdata);
 
         // Mark the submission again.
-        $data = new stdClass();
-        $data->grade = '60.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
+        $this->mark_submission($teacher, $assign, $student, 60.0, [], 1);
 
         // Check the grade exists.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
-        $this->assertEquals(60, (int)$grades[$this->students[0]->id]->rawgrade);
+        $this->setUser($teacher);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
+        $this->assertEquals(60, (int) $grades[$student->id]->rawgrade);
 
         // Check we can reopen still.
-        $result = $assign->testable_process_add_attempt($this->students[0]->id);
+        $result = $assign->testable_process_add_attempt($student->id);
         $this->assertEquals(true, $result);
 
         // Should no longer have a grade because there is no grade for the latest attempt.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
-
     }
 
     /**
@@ -1915,12 +2457,18 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_attempt_reopen_method_untilpass() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
                 'maxattempts' => 3,
                 'submissiondrafts' => 1,
-                'assignsubmission_onlinetext_enabled' => 1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Set grade to pass to 80.
         $gradeitem = $assign->get_grade_item();
@@ -1928,41 +2476,28 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $gradeitem->update();
 
         // Student should be able to see an add submission button.
-        $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->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
 
         // Add a submission.
-        $now = time();
-        $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);
-
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         // Verify the student cannot make a new attempt.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
 
         // Mark the submission as non-passing.
-        $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->mark_submission($teacher, $assign, $student, 50.0);
 
         // Check the student can see the grade.
-        $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->assertNotEquals(false, strpos($output, '50.0'));
 
         // Check that the student now has a button for Add a new attempt.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
 
         // Check that the student now does not have a button for Submit.
@@ -1972,406 +2507,463 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
 
         // Add a second submission.
-        $now = time();
-        $submission = $assign->get_user_submission($this->students[0]->id, true, 1);
-        $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);
-
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         // Mark the submission as passing.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '80.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
+        $this->mark_submission($teacher, $assign, $student, 80.0);
 
         // Check that the student does not have a button for Add a new attempt.
-        $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->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
 
         // Re-mark the submission as not passing.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
+        $this->mark_submission($teacher, $assign, $student, 40.0, [], 1);
 
         // Check that the student now has a button for Add a new attempt.
-        $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->assertRegexp('/' . get_string('addnewattempt', 'assign') . '/', $output);
         $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
+    }
 
-        // Add a submission as a second student.
-        $this->setUser($this->students[1]);
-        $now = time();
-        $submission = $assign->get_user_submission($this->students[1]->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);
+    public function test_attempt_reopen_method_untilpass_passing() {
+        global $PAGE;
 
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[1]->id, true, false);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
+                'maxattempts' => 3,
+                'submissiondrafts' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        // Set grade to pass to 80.
+        $gradeitem = $assign->get_grade_item();
+        $gradeitem->gradepass = '80.0';
+        $gradeitem->update();
+
+        // Student should be able to see an add submission button.
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
+
+        // Add a submission as a student.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
         // Mark the submission as passing.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '100.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 100.0);
 
         // Check the student can see the grade.
-        $this->setUser($this->students[1]);
-        $output = $assign->view_student_summary($this->students[1], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotEquals(false, strpos($output, '100.0'));
 
         // Check that the student does not have a button for Add a new attempt.
-        $output = $assign->view_student_summary($this->students[1], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
+    }
+
+    public function test_attempt_reopen_method_untilpass_no_passing_requirement() {
+        global $PAGE;
+
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
+                'maxattempts' => 3,
+                'submissiondrafts' => 1,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Set grade to pass to 0, so that no attempts should reopen.
         $gradeitem = $assign->get_grade_item();
         $gradeitem->gradepass = '0';
         $gradeitem->update();
 
-        // Add another submission.
-        $this->setUser($this->students[2]);
-        $now = time();
-        $submission = $assign->get_user_submission($this->students[2]->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);
+        // Student should be able to see an add submission button.
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
 
-        // And now submit it for marking.
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[2]->id, true, false);
+        // Add a submission.
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign);
 
-        // Mark the submission as graded.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '0.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
+        // Mark the submission with any grade.
+        $this->mark_submission($teacher, $assign, $student, 0.0);
 
         // Check the student can see the grade.
-        $this->setUser($this->students[2]);
-        $output = $assign->view_student_summary($this->students[2], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotEquals(false, strpos($output, '0.0'));
 
         // Check that the student does not have a button for Add a new attempt.
-        $output = $assign->view_student_summary($this->students[2], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
     }
 
-
+    /**
+     * Test student visibility for each stage of the marking workflow.
+     */
     public function test_markingworkflow() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('markingworkflow'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'markingworkflow' => 1,
+            ]);
+
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Mark the submission and set to notmarked.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED,
+            ]);
 
         // Check the student can't see the grade.
-        $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->assertEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade isn't pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
 
         // Mark the submission and set to inmarking.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_INMARKING,
+            ]);
 
         // Check the student can't see the grade.
-        $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->assertEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade isn't pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
 
         // Mark the submission and set to readyforreview.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW,
+            ]);
 
         // Check the student can't see the grade.
-        $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->assertEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade isn't pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
 
         // Mark the submission and set to inreview.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW,
+            ]);
 
         // Check the student can't see the grade.
-        $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->assertEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade isn't pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
 
         // Mark the submission and set to readyforrelease.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE,
+            ]);
 
         // Check the student can't see the grade.
-        $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->assertEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade isn't pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
         $this->assertEmpty($grades);
 
         // Mark the submission and set to released.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, 50.0,  [
+                'workflowstate' => ASSIGN_MARKING_WORKFLOW_STATE_RELEASED,
+            ]);
 
         // Check the student can see the grade.
-        $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->assertNotEquals(false, strpos($output, '50.0'));
 
         // Make sure the grade is pushed to the gradebook.
-        $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
-        $this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
+        $grades = $assign->get_user_grades_for_gradebook($student->id);
+        $this->assertEquals(50, (int)$grades[$student->id]->rawgrade);
     }
 
+    /**
+     * Test that a student allocated a specific marker is only shown to that marker.
+     */
     public function test_markerallocation() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $otherteacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course, [
+                'markingworkflow' => 1,
+                'markingallocation' => 1
+            ]);
+
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
         // Allocate marker to submission.
-        $data = new stdClass();
-        $data->allocatedmarker = $this->teachers[0]->id;
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $this->mark_submission($teacher, $assign, $student, null, [
+            'allocatedmarker' => $teacher->id,
+        ]);
 
         // Check the allocated marker can view the submission.
-        $this->setUser($this->teachers[0]);
-
+        $this->setUser($teacher);
         $users = $assign->list_participants(0, true);
-        $user = reset($users);
-        $this->assertEquals($this->students[0]->id, $user->id);
+        $this->assertEquals(1, count($users));
+        $this->assertTrue(isset($users[$student->id]));
 
         $cm = get_coursemodule_from_instance('assign', $assign->get_instance()->id);
         $context = context_module::instance($cm->id);
-        $assign = new testable_assign($context, $cm, $this->course);
+        $assign = new testable_assign($context, $cm, $course);
+
         // Check that other teachers can't view this submission.
-        $this->setUser($this->teachers[1]);
+        $this->setUser($otherteacher);
         $users = $assign->list_participants(0, true);
         $this->assertEquals(0, count($users));
     }
 
     /**
-     * @expectedException moodle_exception
+     * Ensure that a teacher cannot submit for students as standard.
      */
     public function test_teacher_submit_for_student() {
         global $PAGE;
 
-        $this->preventResetByRollback();
-        $sink = $this->redirectMessages();
-
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $assign = $this->create_instance($course, [
+            'assignsubmission_onlinetext_enabled' => 1,
+            'submissiondrafts' => 1,
+        ]);
 
-        $this->setUser($this->students[0]);
-        // Simulate a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Student submission text',
-                                         'format'=>FORMAT_MOODLE);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
 
-        $notices = array();
-        $assign->save_submission($data, $notices);
+        // Add a submission but do not submit.
+        $this->add_submission($student, $assign, 'Student submission text');
 
-        // Check that the submission text was saved.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
         $this->assertContains('Student submission text', $output, 'Contains student submission text');
 
-        // Check that a teacher teacher with the extra capability can edit a students submission.
-        $this->setUser($this->teachers[0]);
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Teacher edited submission text',
-                                         'format'=>FORMAT_MOODLE);
+        // Check that a teacher can not edit the submission as they do not have the capability.
+        $this->setUser($teacher);
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage('error/nopermission');
+        $this->add_submission($student, $assign, 'Teacher edited submission text', false);
+    }
+
+    /**
+     * Ensure that a teacher with the editothersubmission capability can submit on behalf of a student.
+     */
+    public function test_teacher_submit_for_student_with_capability() {
+        global $PAGE;
+
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $otherteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+
+        $assign = $this->create_instance($course, [
+            'assignsubmission_onlinetext_enabled' => 1,
+            'submissiondrafts' => 1,
+        ]);
 
         // Add the required capability.
         $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
         assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
-        role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
+        role_assign($roleid, $teacher->id, $assign->get_context()->id);
         accesslib_clear_all_caches_for_unit_testing();
 
-        // Try to save the submission.
-        $notices = array();
-        $assign->save_submission($data, $notices);
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
+
+        // Add a submission but do not submit.
+        $this->add_submission($student, $assign, 'Student submission text');
+
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertContains('Student submission text', $output, 'Contains student submission text');
+
+        // Check that a teacher can edit the submission.
+        $this->setUser($teacher);
+        $this->add_submission($student, $assign, 'Teacher edited submission text', false);
+
+        $this->setUser($student);
+        $output = $assign->view_student_summary($student, true);
+        $this->assertNotContains('Student submission text', $output, 'Contains student submission text');
+        $this->assertContains('Teacher edited submission text', $output, 'Contains teacher edited submission text');
 
         // Check that the teacher can submit the students work.
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $notices = array();
-        $assign->submit_for_grading($data, $notices);
+        $this->setUser($teacher);
+        $this->submit_for_grading($student, $assign, [], false);
 
         // Revert to draft so the student can edit it.
-        $assign->revert_to_draft($this->students[0]->id);
+        $assign->revert_to_draft($student->id);
 
-        $this->setUser($this->students[0]);
+        $this->setUser($student);
 
         // Check that the submission text was saved.
-        $output = $assign->view_student_summary($this->students[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertContains('Teacher edited submission text', $output, 'Contains student submission text');
 
         // Check that the student can submit their work.
-        $data = new stdClass();
-        $assign->submit_for_grading($data, $notices);
+        $this->submit_for_grading($student, $assign, []);
 
-        $output = $assign->view_student_summary($this->students[0], true);
+        $output = $assign->view_student_summary($student, true);
         $this->assertNotContains(get_string('addsubmission', 'assign'), $output);
 
-        // Set to a default editing teacher who should not be able to edit this submission.
-        $this->setUser($this->editingteachers[1]);
+        // An editing teacher without the extra role should still be able to revert to draft.
+        $this->setUser($otherteacher);
 
         // Revert to draft so the submission is editable.
-        $assign->revert_to_draft($this->students[0]->id);
-
-        $data = new stdClass();
-        $data->userid = $this->students[0]->id;
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>'Teacher 2 edited submission text',
-                                         'format'=>FORMAT_MOODLE);
-
-        $notices = array();
-        $assign->save_submission($data, $notices);
-
-        $sink->close();
+        $assign->revert_to_draft($student->id);
     }
 
+    /**
+     * Ensure that disabling submit after the cutoff date works as expected.
+     */
     public function test_disable_submit_after_cutoff_date() {
         global $PAGE;
 
-        $this->setUser($this->editingteachers[0]);
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $now = time();
-        $tomorrow = $now + 24*60*60;
-        $lastweek = $now - 7*24*60*60;
-        $yesterday = $now - 24*60*60;
+        $tomorrow = $now + DAYSECS;
+        $lastweek = $now - (7 * DAYSECS);
+        $yesterday = $now - DAYSECS;
+
+        $this->setAdminUser();
+        $assign = $this->create_instance($course, [
+                'duedate' => $yesterday,
+                'cutoffdate' => $tomorrow,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
 
-        $assign = $this->create_instance(array('duedate'=>$yesterday,
-                                               'cutoffdate'=>$tomorrow,
-                                               'assignsubmission_onlinetext_enabled'=>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]));
 
         // Student should be able to see an add submission button.
-        $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->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
 
         // Add a submission but don't submit now.
-        $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);
 
         // Create another instance with cut-off and due-date already passed.
-        $this->setUser($this->editingteachers[0]);
-        $now = time();
-        $assign = $this->create_instance(array('duedate'=>$lastweek,
-                                               'cutoffdate'=>$yesterday,
-                                               'assignsubmission_onlinetext_enabled'=>1));
+        $this->setAdminUser();
+        $assign = $this->create_instance($course, [
+                'duedate' => $lastweek,
+                'cutoffdate' => $yesterday,
+                'assignsubmission_onlinetext_enabled' => 1,
+            ]);
 
-        $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($output, get_string('editsubmission', 'assign'),
                                  'Should not be able to edit after cutoff date.');
         $this->assertNotContains($output, get_string('submitassignment', 'assign'),
                                  'Should not be able to submit after cutoff date.');
     }
+
     /**
-     * Testing for submission comment plugin settings
+     * Testing for submission comment plugin settings.
+     *
+     * @dataProvider submission_plugin_settings_provider
+     * @param   bool    $globalenabled
+     * @param   array   $instanceconfig
+     * @param   bool    $isenabled
      */
-    public function test_submission_comment_plugin_settings() {
+    public function test_submission_comment_plugin_settings($globalenabled, $instanceconfig, $isenabled) {
         global $CFG;
 
-        $commentconfig = false;
-        if (!empty($CFG->usecomments)) {
-            $commentconfig = $CFG->usecomments;
-        }
-
-        $CFG->usecomments = true;
-        $assign = $this->create_instance();
-        $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(1, $plugin->is_enabled('enabled'));
-
-        $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
-        $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(1, $plugin->is_enabled('enabled'));
-
-        $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
-        $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(1, $plugin->is_enabled('enabled'));
-
-        $CFG->usecomments = false;
-        $assign = $this->create_instance();
-        $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(0, $plugin->is_enabled('enabled'));
-
-        $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
-        $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(0, $plugin->is_enabled('enabled'));
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
 
-        $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
+        $CFG->usecomments = $globalenabled;
+        $assign = $this->create_instance($course, $instanceconfig);
         $plugin = $assign->get_submission_plugin_by_type('comments');
-        $this->assertEquals(0, $plugin->is_enabled('enabled'));
+        $this->assertEquals($isenabled, (bool) $plugin->is_enabled('enabled'));
+    }
 
-        $CFG->usecomments = $commentconfig;
+    public function submission_plugin_settings_provider() {
+        return [
+            'CFG->usecomments true, empty config => Enabled by default' => [
+                true,
+                [],
+                true,
+            ],
+            'CFG->usecomments true, config enabled => Comments enabled' => [
+                true,
+                [
+                    'assignsubmission_comments_enabled' => 1,
+                ],
+                true,
+            ],
+            'CFG->usecomments true, config idisabled => Comments enabled' => [
+                true,
+                [
+                    'assignsubmission_comments_enabled' => 0,
+                ],
+                true,
+            ],
+            'CFG->usecomments false, empty config => Disabled by default' => [
+                false,
+                [],
+                false,
+            ],
+            'CFG->usecomments false, config enabled => Comments disabled' => [
+                false,
+                [
+                    'assignsubmission_comments_enabled' => 1,
+                ],
+                false,
+            ],
+            'CFG->usecomments false, config disabled => Comments disabled' => [
+                false,
+                [
+                    'assignsubmission_comments_enabled' => 0,
+                ],
+                false,
+            ],
+        ];
     }
 
     /**
@@ -2380,6 +2972,11 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
     public function test_feedback_comment_commentinline() {
         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');
+
         $sourcetext = "Hello!
 
 I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
@@ -2411,128 +3008,262 @@ Anchor link 1:Link text
 Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
 ";
 
-        $this->setUser($this->editingteachers[0]);
-        $params = array('assignsubmission_onlinetext_enabled' => 1,
-                        'assignfeedback_comments_enabled' => 1,
-                        'assignfeedback_comments_commentinline' => 1);
-        $assign = $this->create_instance($params);
-
-        $this->setUser($this->students[0]);
-        // Add a submission but don't submit now.
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $data = new stdClass();
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'assignfeedback_comments_enabled' => 1,
+                'assignfeedback_comments_commentinline' => 1,
+            ]);
 
-        // Test the internal link is stripped, but the external one is not.
-        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
-                                         'text'=>$sourcetext,
-                                         'format'=>FORMAT_MOODLE);
+        $this->setUser($student);
 
-        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
-        $plugin->save($submission, $data);
+        // Add a submission but don't submit now.
+        $this->add_submission($student, $assign, $sourcetext);
 
-        $this->setUser($this->editingteachers[0]);
+        $this->setUser($teacher);
 
         $data = new stdClass();
         require_once($CFG->dirroot . '/mod/assign/gradeform.php');
-        $pagination = array('userid'=>$this->students[0]->id,
-                            'rownum'=>0,
-                            'last'=>true,
-                            'useridlistid' => $assign->get_useridlist_key_id(),
-                            'attemptnumber'=>0);
+        $pagination = [
+                'userid' => $student->id,
+                'rownum' => 0,
+                'last' => true,
+                'useridlistid' => $assign->get_useridlist_key_id(),
+                'attemptnumber' => 0,
+            ];
         $formparams = array($assign, $data, $pagination);
-        $mform = new mod_assign_grade_form(null, $formparams);
+        $mform = new mod_assign_grade_form(null, [$assign, $data, $pagination]);
 
         $this->assertEquals($filteredtext, $data->assignfeedbackcomments_editor['text']);
     }
 
     /**
-     * Testing for feedback comment plugin settings
+     * Testing for feedback comment plugin settings.
+     *
+     * @dataProvider feedback_plugin_settings_provider
+     * @param   array   $instanceconfig
+     * @param   bool    $isenabled
      */
-    public function test_feedback_plugin_settings() {
-
-        $assign = $this->create_instance();
-        $plugin = $assign->get_feedback_plugin_by_type('comments');
-        $this->assertEquals(0, $plugin->is_enabled('enabled'));
+    public function test_feedback_plugin_settings($instanceconfig, $isenabled) {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
 
-        $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 0));
+        $assign = $this->create_instance($course, $instanceconfig);
         $plugin = $assign->get_feedback_plugin_by_type('comments');
-        $this->assertEquals(0, $plugin->is_enabled('enabled'));
+        $this->assertEquals($isenabled, (bool) $plugin->is_enabled('enabled'));
+    }
 
-        $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
-        $plugin = $assign->get_feedback_plugin_by_type('comments');
-        $this->assertEquals(1, $plugin->is_enabled('enabled'));
+    public function feedback_plugin_settings_provider() {
+        return [
+            'No configuration => disabled' => [
+                [],
+                false,
+            ],
+            'Actively disabled' => [
+                [
+                    'assignfeedback_comments_enabled' => 0,
+                ],
+                false,
+            ],
+            'Actively enabled' => [
+                [
+                    'assignfeedback_comments_enabled' => 1,
+                ],
+                true,
+            ],
+        ];
     }
 
     /**
      * Testing if gradebook feedback plugin is enabled.
      */
     public function test_is_gradebook_feedback_enabled() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
         $adminconfig = get_config('assign');
         $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
 
         // Create assignment with gradebook feedback enabled and grade = 0.
-        $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 1, 'grades' => 0));
+        $assign = $this->create_instance($course, [
+                "{$gradebookplugin}_enabled" => 1,
+                'grades' => 0,
+            ]);
 
         // Get gradebook feedback plugin.
         $gradebookplugintype = str_replace('assignfeedback_', '', $gradebookplugin);
         $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
         $this->assertEquals(1, $plugin->is_enabled('enabled'));
         $this->assertEquals(1, $assign->is_gradebook_feedback_enabled());
+    }
+
+    /**
+     * Testing if gradebook feedback plugin is disabled.
+     */
+    public function test_is_gradebook_feedback_disabled() {
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $adminconfig = get_config('assign');
+        $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
 
         // Create assignment with gradebook feedback disabled and grade = 0.
-        $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 0, 'grades' => 0));
+        $assign = $this->create_instance($course, [
+                "{$gradebookplugin}_enabled" => 0,
+                'grades' => 0,
+            ]);
+
+        $gradebookplugintype = str_replace('assignfeedback_', '', $gradebookplugin);
         $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
         $this->assertEquals(0, $plugin->is_enabled('enabled'));
     }
 
     /**
-     * Testing can_edit_submission
+     * Testing can_edit_submission.
      */
     public function test_can_edit_submission() {
-        global $PAGE, $DB;
-        $this->create_extra_users();
+        $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');
 
-        $this->setAdminUser();
-        // Create assignment (onlinetext).
-        $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
-        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+            ]);
 
         // Check student can edit their own submission.
-        $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->students[0]->id));
+        $this->assertTrue($assign->can_edit_submission($student->id, $student->id));
+
         // Check student cannot edit others submission.
-        $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->students[1]->id));
+        $this->assertFalse($assign->can_edit_submission($otherstudent->id, $student->id));
 
         // Check teacher cannot (by default) edit a students submission.
-        $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
+        $this->assertFalse($assign->can_edit_submission($student->id, $teacher->id));
+    }
+
+    /**
+     * Testing can_edit_submission with the editothersubmission capability.
+     */
+    public function test_can_edit_submission_with_editothersubmission() {
+        $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');
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+            ]);
 
         // Add the required capability to edit a student submission.
         $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
         assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
-        role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
+        role_assign($roleid, $teacher->id, $assign->get_context()->id);
         accesslib_clear_all_caches_for_unit_testing();
+
+        // Check student can edit their own submission.
+        $this->assertTrue($assign->can_edit_submission($student->id, $student->id));
+
+        // Check student cannot edit others submission.
+        $this->assertFalse($assign->can_edit_submission($otherstudent->id, $student->id));
+
         // Retest - should now have access.
-        $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
+        $this->assertTrue($assign->can_edit_submission($student->id, $teacher->id));
+    }
 
-        // Force create an assignment with SEPARATEGROUPS.
-        $data = new stdClass();
-        $data->courseid = $this->course->id;
-        $data->name = 'Grouping';
-        $groupingid = groups_create_grouping($data);
-        groups_assign_grouping($groupingid, $this->groups[0]->id);
-        groups_assign_grouping($groupingid, $this->groups[1]->id);
-        $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
-
-        // Add the capability to the new assignment for extra students 0 and 1.
+    /**
+     * Testing can_edit_submission
+     */
+    public function test_can_edit_submission_separategroups() {
+        $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');
+        $student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group1->id);
+        groups_add_member($group1, $student1);
+        groups_add_member($group1, $student2);
+
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group2->id);
+        groups_add_member($group2, $student3);
+        groups_add_member($group2, $student4);
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
+
+        // Verify a student does not have the ability to edit submissions for other users.
+        $this->assertTrue($assign->can_edit_submission($student1->id, $student1->id));
+        $this->assertFalse($assign->can_edit_submission($student2->id, $student1->id));
+        $this->assertFalse($assign->can_edit_submission($student3->id, $student1->id));
+        $this->assertFalse($assign->can_edit_submission($student4->id, $student1->id));
+    }
+
+    /**
+     * Testing can_edit_submission
+     */
+    public function test_can_edit_submission_separategroups_with_editothersubmission() {
+        $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');
+        $student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group1->id);
+        groups_add_member($group1, $student1);
+        groups_add_member($group1, $student2);
+
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group2->id);
+        groups_add_member($group2, $student3);
+        groups_add_member($group2, $student4);
+
+        $assign = $this->create_instance($course, [
+                'assignsubmission_onlinetext_enabled' => 1,
+                'submissiondrafts' => 1,
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
+
+        // Add the capability to the new assignment for student 1.
+        $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
         assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
-        role_assign($roleid, $this->extrastudents[0]->id, $assign->get_context()->id);
-        role_assign($roleid, $this->extrastudents[1]->id, $assign->get_context()->id);
+        role_assign($roleid, $student1->id, $assign->get_context()->id);
         accesslib_clear_all_caches_for_unit_testing();
 
-        // Verify the extra student does not have the capability to edit a submission not in their group.
-        $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[1]->id));
-        // Verify the extra student does have the capability to edit a submission in their group.
-        $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[0]->id));
+        // Verify student1 has the ability to edit submissions for other users in their group, but not other groups.
+        $this->assertTrue($assign->can_edit_submission($student1->id, $student1->id));
+        $this->assertTrue($assign->can_edit_submission($student2->id, $student1->id));
+        $this->assertFalse($assign->can_edit_submission($student3->id, $student1->id));
+        $this->assertFalse($assign->can_edit_submission($student4->id, $student1->id));
 
+        // Verify other students do not have the ability to edit submissions for other users.
+        $this->assertTrue($assign->can_edit_submission($student2->id, $student2->id));
+        $this->assertFalse($assign->can_edit_submission($student1->id, $student2->id));
+        $this->assertFalse($assign->can_edit_submission($student3->id, $student2->id));
+        $this->assertFalse($assign->can_edit_submission($student4->id, $student2->id));
     }
 
     /**
@@ -2540,31 +3271,18 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
      */
     public function test_can_view_blind_details() {
         global $DB;
-        // Note: The shared setUp leads to terrible tests. Please don't use it.
-        $roles = $DB->get_records('role', null, '', 'shortname, id');
-        $course = $this->getDataGenerator()->create_course([]);
-
-        $student = $this->students[0];// Get a student user.
-        $this->getDataGenerator()->enrol_user($student->id,
-                                              $course->id,
-                                              $roles['student']->id);
-
-        // Create a teacher. Shouldn't be able to view blind marking ID.
-        $teacher = $this->getDataGenerator()->create_user();
-
-        $this->getDataGenerator()->enrol_user($teacher->id,
-                                              $course->id,
-                                              $roles['teacher']->id);
-
-        // Create a manager.. Should be able to view blind marking ID.
-        $manager = $this->getDataGenerator()->create_user();
-        $this->getDataGenerator()->enrol_user($manager->id,
-                                              $course->id,
-                                              $roles['manager']->id);
-
-        // Generate blind marking assignment.
-        $assign = $this->create_instance(array('course' => $course->id, 'blindmarking' => 1));
-        $this->assertEquals(true, $assign->is_blind_marking());
+
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $manager = $this->getDataGenerator()->create_and_enrol($course, 'manager');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course, [
+                'blindmarking' => 1,
+            ]);
+
+        $this->assertTrue($assign->is_blind_marking());
 
         // Test student names are hidden to teacher.
         $this->setUser($teacher);
@@ -2585,56 +3303,127 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
      * Testing get_shared_group_members
      */
     public function test_get_shared_group_members() {
-        $this->create_extra_users();
-        $this->setAdminUser();
+        $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');
+        $student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group1->id);
+        groups_add_member($group1, $student1);
+        groups_add_member($group1, $student2);
+
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group2->id);
+        groups_add_member($group2, $student3);
+        groups_add_member($group2, $student4);
+
+        $assign = $this->create_instance($course, [
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
+
+        $cm = $assign->get_course_module();
+
+        // Get shared group members for students 0 and 1.
+        $groupmembers = $assign->get_shared_group_members($cm, $student1->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student1->id, $groupmembers);
+        $this->assertContains($student2->id, $groupmembers);
+
+        $groupmembers = $assign->get_shared_group_members($cm, $student2->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student1->id, $groupmembers);
+        $this->assertContains($student2->id, $groupmembers);
+
+        $groupmembers = $assign->get_shared_group_members($cm, $student3->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student3->id, $groupmembers);
+        $this->assertContains($student4->id, $groupmembers);
+
+        $groupmembers = $assign->get_shared_group_members($cm, $student4->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student3->id, $groupmembers);
+        $this->assertContains($student4->id, $groupmembers);
+    }
+
+    /**
+     * Testing get_shared_group_members
+     */
+    public function test_get_shared_group_members_override() {
+        $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');
+        $student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group1->id);
+        groups_add_member($group1, $student1);
+        groups_add_member($group1, $student2);
+
+        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+        groups_assign_grouping($grouping->id, $group2->id);
+        groups_add_member($group2, $student3);
+        groups_add_member($group2, $student4);
+
+        $assign = $this->create_instance($course, [
+                'groupingid' => $grouping->id,
+                'groupmode' => SEPARATEGROUPS,
+            ]);
 
-        // Force create an assignment with SEPARATEGROUPS.
-        $data = new stdClass();
-        $data->courseid = $this->course->id;
-        $data->name = 'Grouping';
-        $groupingid = groups_create_grouping($data);
-        groups_assign_grouping($groupingid, $this->groups[0]->id);
-        groups_assign_grouping($groupingid, $this->groups[1]->id);
-        $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
         $cm = $assign->get_course_module();
 
-        // Add the capability to access allgroups.
+        // Add the capability to access allgroups for one of the students.
         $roleid = create_role('Access all groups role', 'accessallgroupsrole', '');
         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $assign->get_context()->id);
-        role_assign($roleid, $this->extrastudents[3]->id, $assign->get_context()->id);
+        role_assign($roleid, $student1->id, $assign->get_context()->id);
         accesslib_clear_all_caches_for_unit_testing();
 
         // Get shared group members for students 0 and 1.
-        $groupmembers = array();
-        $groupmembers[0] = $assign->get_shared_group_members($cm, $this->students[0]->id);
-        $groupmembers[1] = $assign->get_shared_group_members($cm, $this->students[1]->id);
-
-        // They should share groups with extrastudents 0 and 1.
-        $this->assertTrue(in_array($this->extrastudents[0]->id, $groupmembers[0]));
-        $this->assertFalse(in_array($this->extrastudents[0]->id, $groupmembers[1]));
-        $this->assertTrue(in_array($this->extrastudents[1]->id, $groupmembers[1]));
-        $this->assertFalse(in_array($this->extrastudents[1]->id, $groupmembers[0]));
+        $groupmembers = $assign->get_shared_group_members($cm, $student1->id);
+        $this->assertCount(4, $groupmembers);
+        $this->assertContains($student1->id, $groupmembers);
+        $this->assertContains($student2->id, $groupmembers);
+        $this->assertContains($student3->id, $groupmembers);
+        $this->assertContains($student4->id, $groupmembers);
 
-        // Lists of group members for students and extrastudents should be the same.
-        $this->assertEquals($groupmembers[0], $assign->get_shared_group_members($cm, $this->extrastudents[0]->id));
-        $this->assertEquals($groupmembers[1], $assign->get_shared_group_members($cm, $this->extrastudents[1]->id));
+        $groupmembers = $assign->get_shared_group_members($cm, $student2->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student1->id, $groupmembers);
+        $this->assertContains($student2->id, $groupmembers);
 
-        // Get all group members for extrastudent 3 wich can access all groups.
-        $allgroupmembers = $assign->get_shared_group_members($cm, $this->extrastudents[3]->id);
+        $groupmembers = $assign->get_shared_group_members($cm, $student3->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student3->id, $groupmembers);
+        $this->assertContains($student4->id, $groupmembers);
 
-        // Extrastudent 3 should see students 0 and 1, extrastudent 0 and 1.
-        $this->assertTrue(in_array($this->students[0]->id, $allgroupmembers));
-        $this->assertTrue(in_array($this->students[1]->id, $allgroupmembers));
-        $this->assertTrue(in_array($this->extrastudents[0]->id, $allgroupmembers));
-        $this->assertTrue(in_array($this->extrastudents[1]->id , $allgroupmembers));
+        $groupmembers = $assign->get_shared_group_members($cm, $student4->id);
+        $this->assertCount(2, $groupmembers);
+        $this->assertContains($student3->id, $groupmembers);
+        $this->assertContains($student4->id, $groupmembers);
     }
 
     /**
      * Test get plugins file areas
      */
     public function test_get_plugins_file_areas() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
+        global $DB;
+
+        $this->resetAfterTest();
+        $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+
+        $assign = $this->create_instance($course);
 
         // Test that all the submission and feedback plugins are returning the expected file aras.
         $usingfilearea = 0;
@@ -2689,76 +3478,67 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
     public function test_override_exists() {
         global $DB;
 
-        $this->setAdminUser();
-
+        $this->resetAfterTest();
         $course = $this->getDataGenerator()->create_course();
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 
-        // Create an assign instance.
-        $assign = $this->create_instance(['course' => $course]);
-        $assigninstance = $assign->get_instance();
+        $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]);
 
-        // Create users.
-        $users = [
-            'Only in group A'                     => $this->getDataGenerator()->create_user(),
-            'Only in group B'                     => $this->getDataGenerator()->create_user(),
-            'In group A and B (no user override)' => $this->getDataGenerator()->create_user(),
-            'In group A and B (user override)'    => $this->getDataGenerator()->create_user(),
-            'In no groups'                        => $this->getDataGenerator()->create_user()
-        ];
 
-        // Enrol users.
-        foreach ($users as $user) {
-            $this->getDataGenerator()->enrol_user($user->id, $course->id);
-        }
+        // Data:
+        // - student1 => group A only
+        // - student2 => group B only
+        // - student3 => Group A + Group B (No user override)
+        // - student4 => Group A + Group B (With user override)
+        // - student4 => No groups.
+        $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student1);
+
+        $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group2, $student2);
+
+        $student3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student3);
+        groups_add_member($group2, $student3);
 
-        // Create groups.
-        $groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
-        $groupb = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
-
-        // Add members to groups.
-        // Group A.
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupa->id, 'userid' => $users['Only in group A']->id]);
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupa->id, 'userid' => $users['In group A and B (no user override)']->id]);
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupa->id, 'userid' => $users['In group A and B (user override)']->id]);
-
-        // Group B.
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupb->id, 'userid' => $users['Only in group B']->id]);
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupb->id, 'userid' => $users['In group A and B (no user override)']->id]);
-        $this->getDataGenerator()->create_group_member(
-            ['groupid' => $groupb->id, 'userid' => $users['In group A and B (user override)']->id]);
+        $student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        groups_add_member($group1, $student4);
+        groups_add_member($group2, $student4);
+
+        $student5 = $this->getDataGenerator()->create_and_enrol($course, 'student');
+
+        $assign = $this->create_instance($course);
+        $instance = $assign->get_instance();
 
         // Overrides for each of the groups, and a user override.
         $overrides = [
-            // Override for group A, highest priority (numerically lowest sortorder).
-            [
-                'assignid' => $assigninstance->id,
-                'groupid' => $groupa->id,
+            (object) [
+                // Override for group 1, highest priority (numerically lowest sortorder).
+                'assignid' => $instance->id,
+                'groupid' => $group1->id,
                 'userid' => null,
                 'sortorder' => 1,
                 'allowsubmissionsfromdate' => 1,
                 'duedate' => 2,
                 'cutoffdate' => 3
             ],
-            // Override for group B, lower priority (numerically higher sortorder).
-            [
-                'assignid' => $assigninstance->id,
-                'groupid' => $groupb->id,
+            (object) [
+                // Override for group 2, lower priority (numerically higher sortorder).
+                'assignid' => $instance->id,
+                'groupid' => $group2->id,
                 'userid' => null,
                 'sortorder' => 2,
                 'allowsubmissionsfromdate' => 5,
                 'duedate' => 6,
                 'cutoffdate' => 6
             ],
-            // User override.
-            [
-                'assignid' => $assigninstance->id,
+            (object) [
+                // User override.
+                'assignid' => $instance->id,
                 'groupid' => null,
-                'userid' => $users['In group A and B (user override)']->id,
+                'userid' => $student3->id,
                 'sortorder' => null,
                 'allowsubmissionsfromdate' => 7,
                 'duedate' => 8,
@@ -2766,81 +3546,82 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
             ],
         ];
 
-        // Kinda hacky, need to add the ID to the overrides in the above array
-        // for later.
         foreach ($overrides as &$override) {
-            $override['id'] = $DB->insert_record('assign_overrides', $override);
+            $override->id = $DB->insert_record('assign_overrides', $override);
         }
 
-        $returnedoverrides = array_reduce(array_keys($users), function($carry, $description) use ($users, $assign) {
-            return $carry + ['For user ' . lcfirst($description) => $assign->override_exists($users[$description]->id)];
-        }, []);
-
-        // Test we get back the correct override from override_exists (== checks all object members match).
-        // User only in group A should see the group A override.
-        $this->assertTrue($returnedoverrides['For user only in group A'] == (object)$overrides[0]);
-        // User only in group B should see the group B override.
-        $this->assertTrue($returnedoverrides['For user only in group B'] == (object)$overrides[1]);
-        // User in group A and B, with no user override should see the group A override
-        // as it has higher priority (numerically lower sortorder).
-        $this->assertTrue($returnedoverrides['For user in group A and B (no user override)'] == (object)$overrides[0]);
-        // User in group A and B, with a user override should see the user override
-        // as it has higher priority (numerically lower sortorder).
-        $this->assertTrue($returnedoverrides['For user in group A and B (user override)'] == (object)$overrides[2]);
-        // User with no overrides should get nothing.
-        $this->assertNull($returnedoverrides['For user in no groups']->duedate);
-        $this->assertNull($returnedoverrides['For user in no groups']->cutoffdate);
-        $this->assertNull($returnedoverrides['For user in no groups']->allowsubmissionsfromdate);
+        // User only in group 1 should see the group 1 override.
+        $this->assertEquals($overrides[0], $assign->override_exists($student1->id));
+
+        // User only in group 2 should see the group 2 override.
+        $this->assertEquals($overrides[1], $assign->override_exists($student2->id));
+
+        // User only in both groups with an override should see the user override as it has higher priority.
+        $this->assertEquals($overrides[2], $assign->override_exists($student3->id));
+
+        // User only in both groups with no override should see the group 1 override as it has higher priority.
+        $this->assertEquals($overrides[0], $assign->override_exists($student4->id));
+
+        // User with no overrides shoudl get nothing.
+        $override = $assign->override_exists($student5->id);
+        $this->assertNull($override->duedate);
+        $this->assertNull($override->cutoffdate);
+        $this->assertNull($override->allowsubmissionsfromdate);
     }
 
     /**
      * Test the quicksave grades processor
      */
     public function test_process_save_quick_grades() {
-        $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(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL));
+        $teacher->ignoresesskey = true;
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
+            ]);
 
         // Initially grade the user.
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
-        if (!$grade) {
-            $grade = new stdClass();
-            $grade->attemptnumber = '';
-            $grade->timemodified = '';
-        }
-        $data = array(
-            'grademodified_' . $this->students[0]->id => $grade->timemodified,
-            'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
-            'quickgrade_' . $this->students[0]->id => '60.0'
-        );
+        $grade = (object) [
+                'attemptnumber' => '',
+                'timemodified' => '',
+            ];
+        $data = [
+                "grademodified_{$student->id}" => $grade->timemodified,
+                "gradeattempt_{$student->id}" => $grade->attemptnumber,
+                "quickgrade_{$student->id}" => '60.0',
+            ];
+
         $result = $assign->testable_process_save_quick_grades($data);
         $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertEquals('60.0', $grade->grade);
 
         // Attempt to grade with a past attempts grade info.
-        $assign->testable_process_add_attempt($this->students[0]->id);
+        $assign->testable_process_add_attempt($student->id);
         $data = array(
-            'grademodified_' . $this->students[0]->id => $grade->timemodified,
-            'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
-            'quickgrade_' . $this->students[0]->id => '50.0'
+            'grademodified_' . $student->id => $grade->timemodified,
+            'gradeattempt_' . $student->id => $grade->attemptnumber,
+            'quickgrade_' . $student->id => '50.0'
         );
         $result = $assign->testable_process_save_quick_grades($data);
         $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertFalse($grade);
 
         // Attempt to grade a the attempt.
-        $submission = $assign->get_user_submission($this->students[0]->id, false);
+        $submission = $assign->get_user_submission($student->id, false);
         $data = array(
-            'grademodified_' . $this->students[0]->id => '',
-            'gradeattempt_' . $this->students[0]->id => $submission->attemptnumber,
-            'quickgrade_' . $this->students[0]->id => '40.0'
+            'grademodified_' . $student->id => '',
+            'gradeattempt_' . $student->id => $submission->attemptnumber,
+            'quickgrade_' . $student->id => '40.0'
         );
         $result = $assign->testable_process_save_quick_grades($data);
         $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertEquals('40.0', $grade->grade);
 
         // Catch grade update conflicts.
@@ -2848,19 +3629,19 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
         $pastdata = $data;
         // Update the grade the 'good' way.
         $data = array(
-            'grademodified_' . $this->students[0]->id => $grade->timemodified,
-            'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
-            'quickgrade_' . $this->students[0]->id => '30.0'
+            'grademodified_' . $student->id => $grade->timemodified,
+            'gradeattempt_' . $student->id => $grade->attemptnumber,
+            'quickgrade_' . $student->id => '30.0'
         );
         $result = $assign->testable_process_save_quick_grades($data);
         $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertEquals('30.0', $grade->grade);
 
         // Now update using 'old' data. Should fail.
         $result = $assign->testable_process_save_quick_grades($pastdata);
         $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $grade = $assign->get_user_grade($student->id, false);
         $this->assertEquals('30.0', $grade->grade);
     }
 
@@ -2868,36 +3649,33 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
      * Test updating activity completion when submitting an assessment.
      */
     public function test_update_activity_completion_records_solitary_submission() {
-        $assign = $this->create_instance(array('grade' => 100,
-                'completion' => COMPLETION_TRACKING_AUTOMATIC,
-                'requireallteammemberssubmit' => 0));
-
-        $cm = $assign->get_course_module();
-
-        $student = $this->students[0];
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-
-        $this->setUser($student);
+        $this->resetAfterTest();
 
-        // Simulate a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-            'itemid' => file_get_unused_draft_itemid(),
-            'text' => 'Student submission text',
-            'format' => FORMAT_MOODLE
-        );
-        $completion = new completion_info($this->course);
+        $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $notices = array();
-        $assign->save_submission($data, $notices);
+        $this->setUser($teacher);
+        $assign = $this->create_instance($course, [
+                'grade' => 100,
+                'completion' => COMPLETION_TRACKING_AUTOMATIC,
+                'requireallteammemberssubmit' => 0,
+            ]);
+        $cm = $assign->get_course_module();
 
-        $submission = $assign->get_user_submission($student->id, true);
+        // Submit the assignment as the student.
+        $this->add_submission($student, $assign);
 
         // Check that completion is not met yet.
+        $completion = new completion_info($course);
         $completiondata = $completion->get_data($cm, false, $student->id);
         $this->assertEquals(0, $completiondata->completionstate);
+
+        // Update to mark as complete.
+        $submission = $assign->get_user_submission($student->id, true);
         $assign->testable_update_activity_completion_records(0, 0, $submission,
                 $student->id, COMPLETION_COMPLETE, $completion);
+
         // Completion should now be met.
         $completiondata = $completion->get_data($cm, false, $student->id);
         $this->assertEquals(1, $completiondata->completionstate);
@@ -2907,50 +3685,50 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
      * Test updating activity completion when submitting an assessment.
      */
     public function test_update_activity_completion_records_team_submission() {
-        $assign = $this->create_instance(array('grade' => 100,
-                'completion' => COMPLETION_TRACKING_AUTOMATIC,
-                 'teamsubmission' => 1));
+        $this->resetAfterTest();
 
-        $cm = $assign->get_course_module();
+        $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $otherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
 
-        $student1 = $this->students[0];
-        $student2 = $this->students[1];
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
+        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
 
-        // Put both users into a group.
-        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
-        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student1->id));
-        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student2->id));
+        groups_add_member($group1, $student);
+        groups_add_member($group1, $otherstudent);
 
-        $this->setUser($student1);
+        $assign = $this->create_instance($course, [
+                'grade' => 100,
+                'completion' => COMPLETION_TRACKING_AUTOMATIC,
+                'teamsubmission' => 1,
+            ]);
 
-        // Simulate a submission.
-        $data = new stdClass();
-        $data->onlinetext_editor = array(
-            'itemid' => file_get_unused_draft_itemid(),
-            'text' => 'Student submission text',
-            'format' => FORMAT_MOODLE
-        );
-        $completion = new completion_info($this->course);
+        $cm = $assign->get_course_module();
 
-        $notices = array();
-        $assign->save_submission($data, $notices);
+        $this->add_submission($student, $assign);
+        $this->submit_for_grading($student, $assign, ['groupid' => $group1->id]);
 
-        $submission = $assign->get_user_submission($student1->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $submission->groupid = $group1->id;
+        $completion = new completion_info($course);
 
         // Check that completion is not met yet.
-        $completiondata = $completion->get_data($cm, false, $student1->id);
+        $completiondata = $completion->get_data($cm, false, $student->id);
         $this->assertEquals(0, $completiondata->completionstate);
-        $completiondata = $completion->get_data($cm, false, $student2->id);
+
+        $completiondata = $completion->get_data($cm, false, $otherstudent->id);
         $this->assertEquals(0, $completiondata->completionstate);
-        $assign->testable_update_activity_completion_records(1, 0, $submission, $student1->id,
-                COMPLETION_COMPLETE, $completion);
+
+        $submission = $assign->get_user_submission($student->id, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $submission->groupid = $group1->id;
+
+        $assign->testable_update_activity_completion_records(1, 0, $submission, $student->id, COMPLETION_COMPLETE, $completion);
+
         // Completion should now be met.
-        $completiondata = $completion->get_data($cm, false, $student1->id);
+        $completiondata = $completion->get_data($cm, false, $student->id);
         $this->assertEquals(1, $completiondata->completionstate);
-        $completiondata = $completion->get_data($cm, false, $student2->id);
+
+        $completiondata = $completion->get_data($cm, false, $otherstudent->id);
         $this->assertEquals(1, $completiondata->completionstate);
     }
 
@@ -2992,11 +3770,18 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
 
         $this->resetAfterTest();
 
-        $assign = $this->create_instance(array('grade' => 100));
+        $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, [
+                'grade' => 100,
+            ]);
 
         // Try