From 5515c547688598b29ae96042b3f7941ae1fc06ae Mon Sep 17 00:00:00 2001 From: Charles Connell Date: Sun, 16 Mar 2014 20:49:33 -0400 Subject: [PATCH] Generate test cases at runtime. Not fully working. --- karmaworld/apps/courses/test/test_selenium.py | 315 ++++++++++-------- 1 file changed, 182 insertions(+), 133 deletions(-) diff --git a/karmaworld/apps/courses/test/test_selenium.py b/karmaworld/apps/courses/test/test_selenium.py index 577cbda..e00fbac 100644 --- a/karmaworld/apps/courses/test/test_selenium.py +++ b/karmaworld/apps/courses/test/test_selenium.py @@ -1,5 +1,4 @@ import itertools -from nose import with_setup from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By @@ -7,115 +6,164 @@ from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from django.test import LiveServerTestCase from karmaworld.apps.courses.models import * -import uuid +import new -class AddCourseTest(LiveServerTestCase): - """Tests the Add Course form.""" +class FieldAction: + def __init__(self, field, value, autocomplete, error_expected, new_object_expected=True): + self.field = field + self.value = value + self.autocomplete = autocomplete + self.error_expected = error_expected + self.new_object_expected = new_object_expected + + def __str__(self): + return '{f}: "{v}"'.format(f=self.field, v=self.value) + + def __repr__(self): + return str(self) + + +class CompositeFieldAction: + def __init__(self, subactions, error_expected): + self.subactions = subactions + self.error_expected = error_expected + + def __str__(self): + return str(self.subactions) + + def __repr__(self): + return str(self) + +SCHOOL_FIELD_NAME = 'DepartmentForm-school_text' +COURSE_FIELD_NAME = 'CourseForm-name' +DEPARTMENT_FIELD_NAME = 'DepartmentForm-name_text' +PROFESSOR_FIELD_NAME = 'ProfessorForm-name_text' +PROFESSOR_EMAIL_FIELD_NAME = 'ProfessorForm-email_text' +COURSE_URL_FIELD_NAME = 'CourseForm-url' +HONEYPOT_FIELD_NAME = 'CourseForm-instruction_url' - class FieldAction: - def __init__(self, field, value, autocomplete, error_expected): - self.field = field - self.value = value - self.autocomplete = autocomplete - self.error_expected = error_expected - - def __str__(self): - return "{f}: {v}".format(f=self.field, v=self.value) - - class CompositeFieldAction: - def __init__(self, subactions, error_expected): - self.subactions = subactions - self.error_expected = error_expected - - SCHOOL_FIELD_NAME = 'DepartmentForm-school_text' - COURSE_FIELD_NAME = 'CourseForm-name' - DEPARTMENT_FIELD_NAME = 'DepartmentForm-name_text' - PROFESSOR_FIELD_NAME = 'ProfessorForm-name_text' - PROFESSOR_EMAIL_FIELD_NAME = 'ProfessorForm-email_text' - COURSE_URL_FIELD_NAME = 'CourseForm-url' - HONEYPOT_FIELD_NAME = 'CourseForm-instruction_url' - - EXAMPLE_SCHOOL = 'Northeastern University' - EXAMPLE_NEW_DEPARTMENT = 'College of Arts and Sciences' - EXAMPLE_EXISTING_DEPARTMENT = 'College of Computer and Information Sciences' - EXAMPLE_NEW_PROFESSOR = 'Prof. X' - EXAMPLE_NEW_PROFESSOR_EMAIL = 'xavier@xmen.edu' - EXAMPLE_EXISTING_PROFESSOR = 'Prof. Einstein' - EXAMPLE_EXISTING_PROFESSOR_EMAIL = 'einstein@princeton.edu' - EXAMPLE_NEW_COURSE_NAME = 'Algorithms and Data' - EXAMPLE_EXISTING_COURSE_NAME = 'Theory of Computation' - EXAMPLE_NEW_COURSE_URL = 'http://neu.edu/stuff' - EXAMPLE_HONEYPOT_VALUE = 'Free drugs!' - - SCHOOL_FIELD_OPTIONS = ( - # Choose a school from autocomplete +EXAMPLE_SCHOOL = 'Northeastern University' +EXAMPLE_NEW_DEPARTMENT = 'College of Arts and Sciences' +EXAMPLE_EXISTING_DEPARTMENT = 'College of Computer and Information Sciences' +EXAMPLE_NEW_PROFESSOR = 'Prof. X' +EXAMPLE_NEW_PROFESSOR_EMAIL = 'xavier@xmen.edu' +EXAMPLE_EXISTING_PROFESSOR = 'Prof. Einstein' +EXAMPLE_EXISTING_PROFESSOR_EMAIL = 'einstein@princeton.edu' +EXAMPLE_NEW_COURSE_NAME = 'Algorithms and Data' +EXAMPLE_EXISTING_COURSE_NAME = 'Theory of Computation' +EXAMPLE_NEW_COURSE_URL = 'http://neu.edu/stuff' +EXAMPLE_HONEYPOT_VALUE = 'Free drugs!' + +SCHOOL_DEPARTMENT_FIELD_OPTIONS = ( + # Choose a school from autocomplete + FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=True, error_expected=False), + # Type in a school without choosing from autocomplete + FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=False, error_expected=True), + # Empty school name + FieldAction(SCHOOL_FIELD_NAME, '', autocomplete=False, error_expected=True), + + # Choose school and type in new department + CompositeFieldAction([ FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=True, error_expected=False), - # Type in a school without choosing from autocomplete - FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=False, error_expected=True), - # Empty school name - FieldAction(SCHOOL_FIELD_NAME, '', autocomplete=False, error_expected=True) - ) - - DEPARTMENT_FIELD_OPTIONS = ( - # Type in a new department - FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_NEW_DEPARTMENT, autocomplete=False, error_expected=False), - # Choose an existing department - FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_EXISTING_DEPARTMENT, autocomplete=True, error_expected=False) - ) - - PROFESSOR_FIELDS_OPTIONS = ( - # New name and email typed in - CompositeFieldAction([ - FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_NEW_PROFESSOR, autocomplete=False, error_expected=False), - FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False)], - error_expected=False), - # existing Professor Name selected, matching Professor Email selected - CompositeFieldAction([ - FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False), - FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False)], - error_expected=False), - # existing Professor Name selected, no Email selected - CompositeFieldAction([ - FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False)], - error_expected=False), - # existing Professor Email selected, no Name selected - CompositeFieldAction([ - FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False)], - error_expected=False), - # existing Professor Name selected, different Professor Email selected - CompositeFieldAction([ - FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=False, error_expected=False), - FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False)], - error_expected=True), - ) - - COURSE_FIELD_OPTIONS = ( - # new course name + FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_NEW_DEPARTMENT, autocomplete=False, error_expected=False)], + error_expected=False), + + # Choose school and choose existing department + CompositeFieldAction([ + FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=True, error_expected=False), + FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_EXISTING_DEPARTMENT, autocomplete=True, error_expected=False)], + error_expected=False), +) + +PROFESSOR_FIELDS_OPTIONS = ( + # New name and email typed in + CompositeFieldAction([ + FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_NEW_PROFESSOR, autocomplete=False, error_expected=False), + FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False)], + error_expected=False), + # existing Professor Name selected, matching Professor Email selected + CompositeFieldAction([ + FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False, new_object_expected=False), + FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False, new_object_expected=False)], + error_expected=False), + # existing Professor Name selected, no Email selected + CompositeFieldAction([ + FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False, new_object_expected=False)], + error_expected=False), + # existing Professor Email selected, no Name selected + CompositeFieldAction([ + FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False, new_object_expected=False)], + error_expected=False), + # existing Professor Name selected, different Professor Email selected + CompositeFieldAction([ + FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=False, error_expected=False, new_object_expected=False), + FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False, new_object_expected=False)], + error_expected=True), +) + +COURSE_FIELDS_OPTIONS = ( + # new course name + FieldAction(COURSE_FIELD_NAME, EXAMPLE_NEW_COURSE_NAME, autocomplete=False, error_expected=False), + + # new course name, with a URL + CompositeFieldAction([ FieldAction(COURSE_FIELD_NAME, EXAMPLE_NEW_COURSE_NAME, autocomplete=False, error_expected=False), - # empty course name - FieldAction(COURSE_FIELD_NAME, '', autocomplete=False, error_expected=True) - ) - - COURSE_URL_OPTIONS = ( - # no URL - FieldAction(COURSE_URL_FIELD_NAME, '', autocomplete=False, error_expected=False), - # URL given - FieldAction(COURSE_URL_FIELD_NAME, EXAMPLE_NEW_COURSE_URL, autocomplete=False, error_expected=False) - ) - - HONEYPOT_FIELD_OPTIONS = ( - # something in the honeypot - FieldAction(HONEYPOT_FIELD_NAME, EXAMPLE_HONEYPOT_VALUE, autocomplete=False, error_expected=True), - # nothing in the honeypot - FieldAction(HONEYPOT_FIELD_NAME, '', autocomplete=False, error_expected=False) - ) + FieldAction(COURSE_URL_FIELD_NAME, EXAMPLE_NEW_COURSE_URL, autocomplete=False, error_expected=False)], + error_expected=False), + # empty course name + FieldAction(COURSE_FIELD_NAME, '', autocomplete=False, error_expected=True), + + # empty course name, with a URL + CompositeFieldAction([ + FieldAction(COURSE_FIELD_NAME, '', autocomplete=False, error_expected=True), + FieldAction(COURSE_URL_FIELD_NAME, EXAMPLE_NEW_COURSE_URL, autocomplete=False, error_expected=False)], + error_expected=True), + +) + +HONEYPOT_FIELD_OPTIONS = ( + # something in the honeypot + FieldAction(HONEYPOT_FIELD_NAME, EXAMPLE_HONEYPOT_VALUE, autocomplete=False, error_expected=True), + # nothing in the honeypot + FieldAction(HONEYPOT_FIELD_NAME, '', autocomplete=False, error_expected=False) +) + + +class DynamicTestCasesType(type): + """Borrowed from + http://stackoverflow.com/questions/347574/how-do-i-get-nose-to-discover-dynamically-generated-testcases""" + def __new__(mcs, name, bases, dct): + newdct = dct.copy() + field_options_combinations = itertools.product(SCHOOL_DEPARTMENT_FIELD_OPTIONS, + PROFESSOR_FIELDS_OPTIONS, + COURSE_FIELDS_OPTIONS, + HONEYPOT_FIELD_OPTIONS) + + i = 0 + for actions in field_options_combinations: + def m(self): + self.do_actions(actions) + + test_name = "test_combination_{i}".format(i=i) + m.func_name = test_name + newdct[test_name] = new.function(m.func_code, globals(), test_name, tuple(), m.func_closure) + i += 1 + + + return super(DynamicTestCasesType, mcs).__new__(mcs, name, bases, newdct) + + +class AddCourseTest(LiveServerTestCase): + """Tests the Add Course form.""" + + __metaclass__ = DynamicTestCasesType @classmethod def setUpClass(cls): cls.driver = webdriver.Firefox() cls.driver.implicitly_wait(3) - cls.wait = WebDriverWait(cls.driver, 200) + cls.wait = WebDriverWait(cls.driver, 10) super(AddCourseTest, cls).setUpClass() @classmethod @@ -124,10 +172,10 @@ class AddCourseTest(LiveServerTestCase): super(AddCourseTest, cls).tearDownClass() def set_up(self): - self.northeastern = School.objects.create(name=self.EXAMPLE_SCHOOL, usde_id=33333) - self.department = Department.objects.create(name=self.EXAMPLE_EXISTING_DEPARTMENT, school=self.northeastern) - self.professor = Professor.objects.create(name=self.EXAMPLE_EXISTING_PROFESSOR, email=self.EXAMPLE_EXISTING_PROFESSOR_EMAIL) - self.course = Course.objects.create(name=self.EXAMPLE_EXISTING_COURSE_NAME, department=self.department) + self.northeastern = School.objects.create(name=EXAMPLE_SCHOOL, usde_id=33333) + self.department = Department.objects.create(name=EXAMPLE_EXISTING_DEPARTMENT, school=self.northeastern) + self.professor = Professor.objects.create(name=EXAMPLE_EXISTING_PROFESSOR, email=EXAMPLE_EXISTING_PROFESSOR_EMAIL) + self.course = Course.objects.create(name=EXAMPLE_EXISTING_COURSE_NAME, department=self.department) def tear_down(self): School.objects.all().delete() @@ -150,7 +198,7 @@ class AddCourseTest(LiveServerTestCase): def flatten_actions(actions): results = [] for action in actions: - if isinstance(action, AddCourseTest.CompositeFieldAction): + if isinstance(action, CompositeFieldAction): results.extend(AddCourseTest.flatten_actions(action.subactions)) else: results.append(action) @@ -177,48 +225,49 @@ class AddCourseTest(LiveServerTestCase): def expect_error(self, actions): result = False for action in actions: - if isinstance(action, AddCourseTest.CompositeFieldAction) and \ - self.expect_error(action.subactions): + if isinstance(action, CompositeFieldAction) and \ + (action.error_expected or self.expect_error(action.subactions)): result = True elif action.error_expected: result = True return result - def check_object_exists(self, value, field, exists=True): + def check_object_exists(self, value, field, exists=True, actions=[]): desired_count = 1 if exists else 0 - if field == self.COURSE_FIELD_NAME: - self.assertEqual(Course.objects.filter(name=value).count(), desired_count) - elif field == self.DEPARTMENT_FIELD_NAME: - self.assertEqual(Department.objects.filter(name=value).count(), desired_count) - elif field == self.PROFESSOR_FIELD_NAME: - self.assertEqual(Professor.objects.filter(name=value).count(), desired_count) - elif field == self.PROFESSOR_EMAIL_FIELD_NAME: - self.assertEqual(Professor.objects.filter(email=value).count(), desired_count) - elif field == self.COURSE_URL_FIELD_NAME: - self.assertEqual(Course.objects.filter(url=value).count(), desired_count) - - def actions_test_and_check(self, actions): + if field == COURSE_FIELD_NAME: + self.assertEqual(Course.objects.filter(name=value).count(), desired_count, + 'Expected {n} courses with name "{name}" for actions {a}'. + format(n=desired_count, name=value, a=str(actions))) + elif field == DEPARTMENT_FIELD_NAME: + self.assertEqual(Department.objects.filter(name=value).count(), desired_count, + 'Expected {n} departments with name "{name}" for actions {a}'. + format(n=desired_count, name=value, a=str(actions))) + elif field == PROFESSOR_FIELD_NAME: + self.assertEqual(Professor.objects.filter(name=value).count(), desired_count, + 'Expected {n} professors with name "{name}" for actions {a}'. + format(n=desired_count, name=value, a=str(actions))) + elif field == PROFESSOR_EMAIL_FIELD_NAME: + self.assertEqual(Professor.objects.filter(email=value).count(), desired_count, + 'Expected {n} professors with email "{email}" for actions {a}'. + format(n=desired_count, email=value, a=str(actions))) + elif field == COURSE_URL_FIELD_NAME: + self.assertEqual(Course.objects.filter(url=value).count(), desired_count, + 'Expected {n} courses with url "{url}" for actions {a}'. + format(n=desired_count, url=value, a=str(actions))) + + def do_actions(self, actions): self.set_up() self.driver.get(self.live_server_url) error_expected = self.expect_error(actions) self.fill_out_form(actions) if error_expected: for action in AddCourseTest.flatten_actions(actions): - self.check_object_exists(action.value, action.field, exists=False) + if action.new_object_expected: + self.check_object_exists(action.value, action.field, exists=False, actions=actions) else: for action in AddCourseTest.flatten_actions(actions): - self.check_object_exists(action.value, action.field, exists=True) + if action.new_object_expected: + self.check_object_exists(action.value, action.field, exists=True, actions=actions) self.tear_down() - - def test_combinations(self): - field_options_combinations = itertools.product(self.SCHOOL_FIELD_OPTIONS, - self.DEPARTMENT_FIELD_OPTIONS, - self.PROFESSOR_FIELDS_OPTIONS, - self.COURSE_FIELD_OPTIONS, - self.COURSE_URL_OPTIONS, - self.HONEYPOT_FIELD_OPTIONS) - - for actions in field_options_combinations: - self.actions_test_and_check(actions) -- 2.25.1