def setUp(self): self.config_for_test() self.unit = unit_factory() self.activity = self.unit.discussion_forum self.course = MagicMock() # student recieiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the content unit self.work = fake.text() # Set to none so that loader thinks not a quiz self.activity_id = self.unit.discussion_forum.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects # self.studentRepo = StudentRepository() # self.studentRepo.get_student = MagicMock( return_value=self.reviewer ) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = MagicMock() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)
def setUp( self ): self.config_for_test() env.CONFIG.semester_name = "T30" self.unit = unit_factory() self.course = MagicMock() self.activity_id = self.unit.review.id # self.dao = SqliteDAO() self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content( self.student_ids ) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)
def setUp(self): self.config_for_test() self.unit = unit_factory() self.course = MagicMock() # Set to none so that loader thinks not a quiz self.unit.initial_work.quiz_id = None self.activity_id = self.unit.initial_work.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)
def test_run_some_already_notified( self, workLoaderMock, studentRepoMock, messengerMock ): # Set up status repo with some students already notified num_previously_sent = fake.random.randint( 1, len( self.students ) - 1 ) previously_sent = self.student_ids[ : num_previously_sent ] # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent) to_notify = [ s for s in self.student_ids if s not in previously_sent ] num_to_notify = len( to_notify ) # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content( self.student_ids ) # prepare student repo students = { s.student_id: s for s in self.students } def se( sid ): return students.get( sid ) # set up mocks on instantiated object obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) obj.studentRepo.get_student = MagicMock( side_effect=se ) obj.studentRepo.download = MagicMock( return_value=self.students ) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session # Sets up data for the association repo to use self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students ) reviewers_without_prev_notified_authors = [s.assessor_id for s in self.preexisting_pairings if s.assessee_id not in previously_sent] # setting this since filter step doesn't happen on dummy workRepo.submitter_ids = reviewers_without_prev_notified_authors # workRepo.remove_student_records = MagicMock() workLoaderMock.make = MagicMock( return_value=workRepo ) # Set up previous notifications for sid in previously_sent: obj.feedback_status_repo.record( sid ) # call obj.run() # check self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" ) # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual( messengerMock.call_count, num_to_notify, "Send method called expected number of times" ) messenger_args = [ (c[ 1 ][ 'student_id' ], c[ 1 ][ 'subject' ], c[ 1 ][ 'body' ]) for c in messengerMock.call_args_list ] # Check the content sent for record in obj.associations: # print(record.assessee_id) reviewer_text = workRepo.get_formatted_work_by( record.assessor_id ) # see if sent to assessee sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ] rx = r'{}'.format( reviewer_text ) self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
def test_raises_when_only_one_submission(self, workLoaderMock, studentRepoMock): # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content(self.new_students_ids) workRepo.add_students_to_data(self.student_ids, make_dataframe=True) # Setting to return all the previously assigned students. # this should cause all the students to be filtered out # and the errror raised self.workRepo.submitter_ids = [self.new_students[0]] workLoaderMock.make = MagicMock(return_value=self.workRepo) studentRepoMock.download = MagicMock(return_value=self.students) # call obj = SendInitialWorkToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.preexisting_students) with self.assertRaises(NoAvailablePartner): obj.run()
def setUp(self): self.config_for_test() self.unit = unit_factory() self.activity_data = activity_data_factory() self.activity = Activity(**self.activity_data) # student recieiving the message self.receiving_student = student_factory() self.reviewed_student_work = fake.text() self.studentRepo = StudentRepository() self.studentRepo.get_student = MagicMock( return_value=self.receiving_student) self.contentRepo = ContentRepositoryMock() self.statusRepo = create_autospec(StatusRepository)
class TestUnitTests(TestingBase): """Unit tests with all dependencies mocked""" def setUp( self ): self.config_for_test() env.CONFIG.semester_name = "T30" self.unit = unit_factory() self.course = MagicMock() self.activity_id = self.unit.review.id # self.dao = SqliteDAO() self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content( self.student_ids ) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) def test_instantiates_correct_status_repos( self ): """The sending of metareview results requires a special status repository""" obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) self.assertIsInstance(obj.statusRepos, list, "status repos is a list") self.assertTrue(len(obj.statusRepos) == 2) self.assertIsInstance(obj.invite_status_repo, InvitationStatusRepository, "Invite repo instantiated") self.assertIsInstance( obj.feedback_status_repo, FeedbackStatusRepository, "Correct status repo instantiated" )
def setUp(self): self.config_for_test() self.unit = unit_factory() # self.activity_data = activity_data_factory() self.activity = self.unit.review #InitialWork( **self.activity_data ) # student recieiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the content unit self.work = fake.text() self.studentRepo = StudentRepository() self.studentRepo.get_student = MagicMock(return_value=self.reviewer) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = MagicMock() #create_autospec(StatusRepository)
def setUp( self ): self.config_for_test() self.unit = unit_factory() self.activity = self.unit.metareview # student receiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the results of the peer review self.work = fake.text() self.studentRepo = StudentRepository() # self.studentRepo.data = {self.author.id : self.author, # self.reviewer.id: self.reviewer # } self.studentRepo.get_student = MagicMock( return_value=self.author ) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work ) self.statusRepo = create_autospec(InvitationStatusRepository) self.review_assign = MagicMock( assessor_id=self.reviewer.id, assessee_id=self.author.id )
def setUp(self): self.config_for_test() self.unit = unit_factory() # self.activity_data = activity_data_factory() self.activity = self.unit.metareview #InitialWork( **self.activity_data ) self.author = student_factory() # student receiving the message (we are sending the feedback # created by the author of the content assignment) self.reviewer = student_factory() # This would be metareview feedback on the review self.work = fake.text() self.studentRepo = StudentRepository() self.studentRepo.get_student = MagicMock(return_value=self.reviewer) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = create_autospec(FeedbackStatusRepository)
def test_run( self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock, inviteStatusRepoMock ): # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content( self.student_ids ) workRepo.submitter_ids = self.student_ids workRepo.remove_student_records = MagicMock() workLoaderMock.make = MagicMock( return_value=workRepo ) # prepare student repo students = { s.student_id: s for s in self.students } def se( sid ): return students.get( sid ) # call obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) obj.studentRepo.get_student = MagicMock( side_effect=se ) obj.studentRepo.download = MagicMock( return_value=self.students ) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session # Sets up data for the association repo to use self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students ) obj.run() # check self.assertEqual( len( obj.associations ), len( self.students ), "Correct number of students notified" ) # Check that filtered previously notified workRepo.remove_student_records.assert_called() # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual( messengerMock.call_count, len( self.students ), "Send method called expected number of times" ) messenger_args = [ (c[ 1 ][ 'student_id' ], c[ 1 ][ 'subject' ], c[ 1 ][ 'body' ]) for c in messengerMock.call_args_list ] # Check that all messages have the correct subject for sid, subj, body in messenger_args: self.assertEqual(self.unit.metareview.email_subject, subj, "Correct subject line") # Status repo calls on messenger for repo in obj.messenger.status_repositories: repo.record.assert_called() # obj.messenger.status_repositories.record_invited.assert_called() call_list = repo.record.call_args_list # call_list = obj.messenger.status_repositories.record_invited.call_args_list status_args = [ c[ 0 ][ 0 ] for c in call_list ] self.assertEqual( len( self.students ), len( call_list ), "Status repo record called expected number of times" ) for sid in self.student_ids: self.assertIn( sid, status_args, "Record called on both repos for all students" ) # student repo calls on messenger for sid in self.student_ids: obj.messenger.student_repository.get_student.assert_any_call( sid ) # Check the content sent for record in obj.associations: # print(record.assessee_id) reviewer_text = workRepo.get_formatted_work_by( record.assessor_id ) # see if sent to assessee sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ] rx = r'{}'.format( reviewer_text ) self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
class TestFunctionalTests( TestingBase ): """Checks that works properly on first run after deadline on work that has been submitted """ def setUp( self ): self.config_for_test() env.CONFIG.semester_name = "T30" self.unit = unit_factory() self.course = MagicMock() self.activity_id = self.unit.review.id # self.dao = SqliteDAO() self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content( self.student_ids ) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.InvitationStatusRepository' ) @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.FeedbackStatusRepository' ) @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' ) @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' ) @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' ) def test_run( self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock, inviteStatusRepoMock ): # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content( self.student_ids ) workRepo.submitter_ids = self.student_ids workRepo.remove_student_records = MagicMock() workLoaderMock.make = MagicMock( return_value=workRepo ) # prepare student repo students = { s.student_id: s for s in self.students } def se( sid ): return students.get( sid ) # call obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) obj.studentRepo.get_student = MagicMock( side_effect=se ) obj.studentRepo.download = MagicMock( return_value=self.students ) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session # Sets up data for the association repo to use self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students ) obj.run() # check self.assertEqual( len( obj.associations ), len( self.students ), "Correct number of students notified" ) # Check that filtered previously notified workRepo.remove_student_records.assert_called() # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual( messengerMock.call_count, len( self.students ), "Send method called expected number of times" ) messenger_args = [ (c[ 1 ][ 'student_id' ], c[ 1 ][ 'subject' ], c[ 1 ][ 'body' ]) for c in messengerMock.call_args_list ] # Check that all messages have the correct subject for sid, subj, body in messenger_args: self.assertEqual(self.unit.metareview.email_subject, subj, "Correct subject line") # Status repo calls on messenger for repo in obj.messenger.status_repositories: repo.record.assert_called() # obj.messenger.status_repositories.record_invited.assert_called() call_list = repo.record.call_args_list # call_list = obj.messenger.status_repositories.record_invited.call_args_list status_args = [ c[ 0 ][ 0 ] for c in call_list ] self.assertEqual( len( self.students ), len( call_list ), "Status repo record called expected number of times" ) for sid in self.student_ids: self.assertIn( sid, status_args, "Record called on both repos for all students" ) # student repo calls on messenger for sid in self.student_ids: obj.messenger.student_repository.get_student.assert_any_call( sid ) # Check the content sent for record in obj.associations: # print(record.assessee_id) reviewer_text = workRepo.get_formatted_work_by( record.assessor_id ) # see if sent to assessee sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ] rx = r'{}'.format( reviewer_text ) self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" ) @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' ) @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' ) @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' ) def test_run_some_already_notified( self, workLoaderMock, studentRepoMock, messengerMock ): # Set up status repo with some students already notified num_previously_sent = fake.random.randint( 1, len( self.students ) - 1 ) previously_sent = self.student_ids[ : num_previously_sent ] # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent) to_notify = [ s for s in self.student_ids if s not in previously_sent ] num_to_notify = len( to_notify ) # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content( self.student_ids ) # prepare student repo students = { s.student_id: s for s in self.students } def se( sid ): return students.get( sid ) # set up mocks on instantiated object obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) obj.studentRepo.get_student = MagicMock( side_effect=se ) obj.studentRepo.download = MagicMock( return_value=self.students ) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session # Sets up data for the association repo to use self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students ) reviewers_without_prev_notified_authors = [s.assessor_id for s in self.preexisting_pairings if s.assessee_id not in previously_sent] # setting this since filter step doesn't happen on dummy workRepo.submitter_ids = reviewers_without_prev_notified_authors # workRepo.remove_student_records = MagicMock() workLoaderMock.make = MagicMock( return_value=workRepo ) # Set up previous notifications for sid in previously_sent: obj.feedback_status_repo.record( sid ) # call obj.run() # check self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" ) # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual( messengerMock.call_count, num_to_notify, "Send method called expected number of times" ) messenger_args = [ (c[ 1 ][ 'student_id' ], c[ 1 ][ 'subject' ], c[ 1 ][ 'body' ]) for c in messengerMock.call_args_list ] # Check the content sent for record in obj.associations: # print(record.assessee_id) reviewer_text = workRepo.get_formatted_work_by( record.assessor_id ) # see if sent to assessee sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ] rx = r'{}'.format( reviewer_text ) self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" ) @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' ) @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' ) @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' ) def test_run_some_not_turned_in( self, workLoaderMock, studentRepoMock, messengerMock ): # Set up status repo with some students already notified num_unsubmitted = fake.random.randint( 1, len( self.students ) - 1 ) submitted = self.student_ids[ : num_unsubmitted ] # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent) to_notify = [ s for s in self.student_ids if s in submitted ] num_to_notify = len( to_notify ) # feedbackStatusRepoMock.previously_sent_result = MagicMock( return_value=previously_sent ) # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content( self.student_ids ) workRepo.submitter_ids = to_notify workLoaderMock.make = MagicMock( return_value=workRepo ) # prepare student repo students = { s.student_id: s for s in self.students } def se( sid ): return students.get( sid ) # set up mocks on instantiated object obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True ) obj.studentRepo.get_student = MagicMock( side_effect=se ) obj.studentRepo.download = MagicMock( return_value=self.students ) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session # Sets up data for the association repo to use self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students ) # call obj.run() # check self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" ) # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual( messengerMock.call_count, num_to_notify, "Send method called expected number of times" ) messenger_args = [ (c[ 1 ][ 'student_id' ], c[ 1 ][ 'subject' ], c[ 1 ][ 'body' ]) for c in messengerMock.call_args_list ] # Check the content sent for record in obj.associations: # print(record.assessee_id) reviewer_text = workRepo.get_formatted_work_by( record.assessor_id ) # see if sent to assessee sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ] rx = r'{}'.format( reviewer_text ) self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
class TestUnitTests(TestingBase): def setUp(self): self.config_for_test() self.unit = unit_factory() self.activity = self.unit.discussion_forum self.course = MagicMock() # student recieiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the content unit self.work = fake.text() # Set to none so that loader thinks not a quiz self.activity_id = self.unit.discussion_forum.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects # self.studentRepo = StudentRepository() # self.studentRepo.get_student = MagicMock( return_value=self.reviewer ) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = MagicMock() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) def test_instantiates_correct_status_repo(self): """The sending of metareview results requires a special status repository""" obj = SendForumPostsToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) self.assertEqual(len(obj.statusRepos), 1, "expected number of status repos") self.assertIsInstance(obj.statusRepos[0], InvitationStatusRepository, "Correct status repo instantiated") def test__message_step(self): self.skipTest("todo") def test__assign_step(self): self.skipTest("todo") @patch('CanvasHacks.SkaaSteps.ISkaaSteps.DisplayManager') @patch( 'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.WorkRepositoryLoaderFactory' ) def test__load_step(self, workLoaderMock, displayManagerMock): self.workRepo.remove_student_records = MagicMock() workLoaderMock.make = MagicMock(return_value=self.workRepo) obj = SendForumPostsToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) # call obj._load_step() # check workLoaderMock.make.assert_called() displayManagerMock.assert_called() call_args = [c[0][0] for c in workLoaderMock.call_args_list]
class TestFunctionalTests(TestingBase): def setUp(self): self.config_for_test() self.unit = unit_factory() self.activity = self.unit.discussion_forum self.course = MagicMock() # student recieiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the content unit self.work = fake.text() # Set to none so that loader thinks not a quiz self.activity_id = self.unit.discussion_forum.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects # self.studentRepo = StudentRepository() # self.studentRepo.get_student = MagicMock( return_value=self.reviewer ) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = MagicMock() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) @patch( 'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.InvitationStatusRepository' ) @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send') @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.WorkRepositoryLoaderFactory' ) def test_run(self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock): self.workRepo.submitter_ids = self.new_students_ids workLoaderMock.make = MagicMock(return_value=self.workRepo) # prepare student repo students = {s.student_id: s for s in self.students} def se(sid): return students.get(sid) # studentRepoMock.get_student = MagicMock(side_effect=se) # studentRepoMock.download = MagicMock( return_value=self.students ) # call obj = SendForumPostsToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) # obj.studentRepo = MagicMock() obj.studentRepo.get_student = MagicMock(side_effect=se) obj.studentRepo.download = MagicMock(return_value=self.students) preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.preexisting_students, obj.dao.session) obj.run() # check self.assertEqual(len(obj.associations), len(self.new_students_ids), "Correct number of students assigned") # Check that new assignments don't involve previously assigned sudents for rec in obj.associations: self.assertNotIn( rec.assessor_id, self.preexisting_student_ids, "Newly assigned assessor not among previously assigned students" ) self.assertNotIn( rec.assessee_id, self.preexisting_student_ids, "Newly assigned assessee not among previously assigned students" ) # Check whether each new student has been assigned new_assessor_ids = [r.assessor_id for r in obj.associations] new_assessee_ids = [r.assessee_id for r in obj.associations] self.assertEqual(len(set(new_assessor_ids)), len(self.new_students_ids), "No duplicate assessor assignments") self.assertEqual(len(set(new_assessee_ids)), len(self.new_students_ids), "No duplicate assessee assignments") for sid in self.new_students_ids: self.assertIn(sid, new_assessee_ids, "Student is an assessee") self.assertIn(sid, new_assessor_ids, "Student is an assessor") # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual(messengerMock.call_count, len(self.new_students_ids), "Send method called expected number of times") messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body']) for c in messengerMock.call_args_list] # print(args) # Check that all messages have the correct subject for sid, subj, body in messenger_args: self.assertEqual(self.unit.discussion_review.email_subject, subj, "Correct subject line") # Status repo calls on messenger obj.messenger.status_repositories[0].record.assert_called() call_list = obj.messenger.status_repositories[0].record.call_args_list # obj.messenger.status_repositories.record_invited.assert_called() # call_list = obj.messenger.status_repositories.record_invited.call_args_list status_args = [c[0][0] for c in call_list] self.assertEqual( len(self.new_students), len(call_list), "Status repo record_invited called expected number of times") for sid in self.new_students_ids: self.assertIn(sid, status_args, "StatusRepo.record_invited called on all students") # student repo calls on messenger for sid in self.new_students_ids: obj.messenger.student_repository.get_student.assert_any_call(sid) # Check the content sent for record in obj.associations: # print(record.assessee_id) author_text = self.workRepo.get_formatted_work_by( record.assessee_id) # see if sent to assessor sent_text = [ t[2] for t in messenger_args if t[0] == record.assessor_id ][0] rx = r'{}'.format(author_text) self.assertRegex(sent_text, rx, "Author's work in message sent to reviewer") def test_audit_frame(self): self.skipTest("todo")
class TestFunctionalTests(TestingBase): def setUp(self): self.config_for_test() self.unit = unit_factory() self.activity = self.unit.discussion_review self.course = MagicMock() # student recieiving the message self.author = student_factory() self.reviewer = student_factory() # This would be the content unit self.work = fake.text() # Set to none so that loader thinks not a quiz self.activity_id = self.unit.discussion_review.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects # self.studentRepo = StudentRepository() # self.studentRepo.get_student = MagicMock( return_value=self.reviewer ) self.contentRepo = ContentRepositoryMock() self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work) self.review_assign = MagicMock(assessor_id=self.reviewer.id, assessee_id=self.author.id) self.statusRepo = MagicMock() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) def test_instantiates_w_correct_values(self): """Dummy checking in case some of the main variables used change""" obj = SendDiscussionReviewToPoster(course=self.course, unit=self.unit, is_test=True, send=True) self.assertIsInstance(obj.statusRepos[0], FeedbackStatusRepository, "Correct status repo instantiated") self.assertEqual(obj.statusRepos[0].activity, self.activity, "Status repo instantiated with correct activity") self.assertIsInstance(obj.activity_notifying_about, DiscussionReview, "Notifying about expected type of activity") self.assertEqual(obj.activity_notifying_about, self.unit.discussion_review, "Expected activity") self.assertIsInstance( obj.activity_for_review_pairings, DiscussionReview, "Review pairings based on expected activity type: Discussion review" ) self.assertEqual(obj.activity_for_review_pairings, self.unit.discussion_review, "Expected activity") self.assertIsInstance( obj.activity, DiscussionReview, "Working on results from expected activity type") self.assertEqual(obj.activity, self.unit.discussion_review, "Expected activity") @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send') @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendDiscussionReviewToPoster.WorkRepositoryLoaderFactory' ) def test_run_first_time_for_activity(self, workLoaderMock, studentRepoMock, messengerMock): # even though this will be the result of the filtering # we need to limit here since the mock doesn't have the property self.workRepo.submitter_ids = self.student_ids workLoaderMock.make = MagicMock(return_value=self.workRepo) students = {s.student_id: s for s in self.students} def se(sid): return students.get(sid) obj = SendDiscussionReviewToPoster(course=self.course, unit=self.unit, is_test=True, send=True) # setup students obj.studentRepo.get_student = MagicMock(side_effect=se) obj.studentRepo.download = MagicMock(return_value=self.students) # setup review pairings preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.students, obj.dao.session) obj.statusRepos = [ create_autospec(FeedbackStatusRepository, previously_sent_students=[]) ] # call obj.run() # ================== Events on Messenger # Check that mocked objects were called with expected data # Every student should've been messaged messengerMock.assert_called() self.assertEqual(messengerMock.call_count, len(self.student_ids), "Send method called expected number of times") messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body']) for c in messengerMock.call_args_list] # Check that all messages have the correct subject for sid, subj, body in messenger_args: expect_subj = FeedbackFromDiscussionReviewMessenger.email_subject_templ.format( self.unit.unit_number) self.assertEqual(expect_subj, subj, "Correct subject line") # Status repo calls on messenger obj.messenger.status_repositories[0].record.assert_called() call_list = obj.messenger.status_repositories[0].record.call_args_list status_args = [c[0][0] for c in call_list] self.assertEqual(len(self.student_ids), len(call_list), "Status repo record called expected number of times") for sid in self.student_ids: self.assertIn(sid, status_args, "StatusRepo.record called on all students") # student repo calls on messenger for sid in self.student_ids: obj.messenger.student_repository.get_student.assert_any_call(sid) # Check the content sent for record in obj.associations: # This is the review which the assessor has submitted author_text = self.workRepo.get_formatted_work_by( record.assessor_id) # which we are sending to the person who created the posts sent_text = [ t[2] for t in messenger_args if t[0] == record.assessee_id ][0] rx = r'{}'.format(author_text) self.assertRegex(sent_text, rx, "Author's work in message sent to reviewer") # @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.FeedbackStatusRepository' ) @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send') @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendDiscussionReviewToPoster.WorkRepositoryLoaderFactory' ) def test_run_previously_sent(self, workLoaderMock, studentRepoMock, messengerMock): authors_who_have_not_been_notified = self.new_students_ids authors_who_have_been_previously_notified = self.preexisting_student_ids students = {s.student_id: s for s in self.students} def se(sid): return students.get(sid) obj = SendDiscussionReviewToPoster(course=self.course, unit=self.unit, is_test=True, send=True) # setup students obj.studentRepo.get_student = MagicMock(side_effect=se) obj.studentRepo.download = MagicMock(return_value=self.students) # setup review pairings preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.students, obj.dao.session) reviewers_with_notified_authors = [ r.assessor_id for r in preexisting_pairings if r.assessee_id in authors_who_have_been_previously_notified ] reviewers_without_notified_authors = [ s for s in self.student_ids if s not in reviewers_with_notified_authors ] obj.statusRepos = [ create_autospec( FeedbackStatusRepository, reviewers_with_notified_authors=reviewers_with_notified_authors ) ] # This will be handled by the _filter_notified step. But since # we are using a dummy work repo, calling remove_student_records won't do anything # Thus we need to pretend that it did its job. (We've tested it elsewhere) self.workRepo.submitter_ids = reviewers_without_notified_authors workLoaderMock.make = MagicMock(return_value=self.workRepo) # call obj.run() # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual(messengerMock.call_count, len(authors_who_have_not_been_notified), "Send method called expected number of times") messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body']) for c in messengerMock.call_args_list] # Check that all messages have the correct subject for sid, subj, body in messenger_args: expect_subj = FeedbackFromDiscussionReviewMessenger.email_subject_templ.format( self.unit.unit_number) self.assertEqual(expect_subj, subj, "Correct subject line") # Status repo calls on messenger which # record the message having been sent to authors obj.messenger.status_repositories[0].record.assert_called() call_list = obj.messenger.status_repositories[0].record.call_args_list status_args = [c[0][0] for c in call_list] self.assertEqual(len(authors_who_have_not_been_notified), len(call_list), "Status repo record called expected number of times") for sid in authors_who_have_not_been_notified: self.assertIn( sid, status_args, "StatusRepo.record called on authors who have now received their feedback (i.e., from newly submitted reviewers)" ) # student repo calls on messenger for sid in authors_who_have_not_been_notified: obj.messenger.student_repository.get_student.assert_any_call(sid) # Check the content sent for record in obj.associations: # This is the review which the assessor has submitted author_text = self.workRepo.get_formatted_work_by( record.assessor_id) # which we are sending to the person who created the posts sent_text = [ t[2] for t in messenger_args if t[0] == record.assessee_id ][0] rx = r'{}'.format(author_text) self.assertRegex(sent_text, rx, "Author's work in message sent to reviewer")
class TestFunctionalTestWhenNonQuizType(TestingBase): """ Tests the entire process in various use cases using local data when the unit is NOT some flavor of quiz (and thus does not use a quiz report) For tests of whole process which hit server, see tests.EndToEnd """ def setUp(self): self.config_for_test() self.unit = unit_factory() self.course = MagicMock() # Set to none so that loader thinks not a quiz self.unit.initial_work.quiz_id = None self.activity_id = self.unit.initial_work.id self.dao = SqliteDAO() self.session = self.dao.session self.create_new_and_preexisting_students() # Prepare fake work repo to give values to calling objects self.workRepo = ContentRepositoryMock() self.workRepo.create_test_content(self.student_ids) self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True) # workRepo = create_autospec( QuizRepository ) # workRepo.get_formatted_work_by = MagicMock( return_value=testText ) @patch( 'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.InvitationStatusRepository' ) @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send') @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory' ) def test_does_not_send_to_people_already_assigned(self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock): """ Simulates a run where some students have already been assigned peer reviewers and a new group is being processed. Focus in testing is on making sure that the two groups don't get mixed up :param workLoaderMock: :param studentRepoMock: :param messengerMock: :return: """ self.workRepo.submitter_ids = self.new_students_ids workLoaderMock.make = MagicMock(return_value=self.workRepo) # prepare student repo students = {s.student_id: s for s in self.students} def se(sid): return students.get(sid) # studentRepoMock.get_student = MagicMock(side_effect=se) # studentRepoMock.download = MagicMock( return_value=self.students ) # call obj = SendInitialWorkToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) # obj.studentRepo = MagicMock() obj.studentRepo.get_student = MagicMock(side_effect=se) obj.studentRepo.download = MagicMock(return_value=self.students) preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.preexisting_students, obj.dao.session) obj.run() # check self.assertEqual(len(obj.associations), len(self.new_students_ids), "Correct number of students assigned") # Check that new assignments don't involve previously assigned sudents for rec in obj.associations: self.assertNotIn( rec.assessor_id, self.preexisting_student_ids, "Newly assigned assessor not among previously assigned students" ) self.assertNotIn( rec.assessee_id, self.preexisting_student_ids, "Newly assigned assessee not among previously assigned students" ) # Check whether each new student has been assigned new_assessor_ids = [r.assessor_id for r in obj.associations] new_assessee_ids = [r.assessee_id for r in obj.associations] self.assertEqual(len(set(new_assessor_ids)), len(self.new_students_ids), "No duplicate assessor assignments") self.assertEqual(len(set(new_assessee_ids)), len(self.new_students_ids), "No duplicate assessee assignments") for sid in self.new_students_ids: self.assertIn(sid, new_assessee_ids, "Student is an assessee") self.assertIn(sid, new_assessor_ids, "Student is an assessor") # ================== Events on Messenger # Check that mocked objects were called with expected data messengerMock.assert_called() self.assertEqual(messengerMock.call_count, len(self.new_students_ids), "Send method called expected number of times") messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body']) for c in messengerMock.call_args_list] # print(args) # Check that all messages have the correct subject for sid, subj, body in messenger_args: self.assertEqual(self.unit.review.email_subject, subj, "Correct subject line") # Status repo calls on messenger (only 1 repo) obj.messenger.status_repositories[0].record.assert_called() call_list = obj.messenger.status_repositories[0].record.call_args_list # obj.messenger.status_repositories.record_invited.assert_called() # call_list = obj.messenger.status_repositories.record_invited.call_args_list status_args = [c[0][0] for c in call_list] self.assertEqual( len(self.new_students), len(call_list), "Status repo record_invited called expected number of times") for sid in self.new_students_ids: self.assertIn(sid, status_args, "StatusRepo.record_invited called on all students") # student repo calls on messenger for sid in self.new_students_ids: obj.messenger.student_repository.get_student.assert_any_call(sid) # Check the content sent for record in obj.associations: # print(record.assessee_id) author_text = self.workRepo.get_formatted_work_by( record.assessee_id) # see if sent to assessor sent_text = [ t[2] for t in messenger_args if t[0] == record.assessor_id ][0] rx = r'{}'.format(author_text) self.assertRegex(sent_text, rx, "Author's work in message sent to reviewer") @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory' ) def test_raises_when_all_submitters_already_assigned( self, workLoaderMock, studentRepoMock): # Prepare fake work repo to give values to calling objects # workRepo = ContentRepositoryMock() # workRepo.create_test_content( self.preexisting_student_ids ) # workRepo.add_students_to_data(self.student_ids, make_dataframe=True) # Setting to return all the previously assigned students. # this should cause all the students to be filtered out # and the errror raised self.workRepo.submitter_ids = self.preexisting_student_ids workLoaderMock.make = MagicMock(return_value=self.workRepo) studentRepoMock.download = MagicMock(return_value=self.students) # call obj = SendInitialWorkToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) self.session = obj.dao.session preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.preexisting_students) with self.assertRaises(AllAssigned): obj.run() @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository') @patch( 'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory' ) def test_raises_when_only_one_submission(self, workLoaderMock, studentRepoMock): # Prepare fake work repo to give values to calling objects workRepo = ContentRepositoryMock() workRepo.create_test_content(self.new_students_ids) workRepo.add_students_to_data(self.student_ids, make_dataframe=True) # Setting to return all the previously assigned students. # this should cause all the students to be filtered out # and the errror raised self.workRepo.submitter_ids = [self.new_students[0]] workLoaderMock.make = MagicMock(return_value=self.workRepo) studentRepoMock.download = MagicMock(return_value=self.students) # call obj = SendInitialWorkToReviewer(course=self.course, unit=self.unit, is_test=True, send=True) # Have to do this after object creation so that we can use the # same in-memory db self.session = obj.dao.session preexisting_pairings = self.create_preexisting_review_pairings( self.activity_id, self.preexisting_students) with self.assertRaises(NoAvailablePartner): obj.run()