Repository: uccser/cs-unplugged

Issue:
Complete folder structure for test suite
Each file should have a docstring explaining it's intended purpose.
Add a code coverage tool



Discussion:

Resolving patch:
diff --git a/csunplugged/utils/BaseLoader.py b/csunplugged/utils/BaseLoader.py
--- a/csunplugged/utils/BaseLoader.py
+++ b/csunplugged/utils/BaseLoader.py
@@ -10,7 +10,6 @@
 from verto import Verto
 
 from .check_required_files import check_converter_required_files
-
 from utils.errors.CouldNotFindMarkdownFileError import CouldNotFindMarkdownFileError
 from utils.errors.EmptyMarkdownFileError import EmptyMarkdownFileError
 from utils.errors.EmptyConfigFileError import EmptyConfigFileError


Test patch:
diff --git a/csunplugged/tests/BaseTest.py b/csunplugged/tests/BaseTest.py
--- a/csunplugged/tests/BaseTest.py
+++ b/csunplugged/tests/BaseTest.py
@@ -1,35 +1,40 @@
 """Base test class with methods implemented for Django testing."""
 
-from django.test import TestCase
-from django.contrib.auth.models import User
+from django.test import SimpleTestCase
 from django.test.client import Client
 from django.utils.translation import activate
 
 
-class BaseTest(TestCase):
+class BaseTest(SimpleTestCase):
     """Base test class with methods implemented for Django testing."""
 
     def __init__(self, *args, **kwargs):
         """Create the BaseTest object by calling the parent's constructor."""
-        TestCase.__init__(self, *args, **kwargs)
+        super().__init__(*args, **kwargs)
+        self.language = None
+
+    @classmethod
+    def setUpClass(cls):
+        """Automatically called before tests in class."""
+        super(BaseTest, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        """Automatically called after each test."""
+        super(BaseTest, cls).tearDownClass()
 
     def setUp(self):
         """Automatically called before each test.
 
-        Sets the language to English, creates a new user and logs into the database.
+        Sets the language if specified and creates a new client.
         """
-        activate('en')
+        if self.language is not None:
+            activate(self.language)
         self.client = Client()
-        self.username = 'test'
-        self.email = 'test@test.com'
-        self.password = 'test'
-        self.test_user = User.objects.create_user(self.username, self.email, self.password)
-        login = self.client.login(username=self.username, password=self.password)
-        self.assertEqual(login, True)
 
     def tearDown(self):
         """Automatically called after each test.
 
         Deletes test user.
         """
-        self.test_user.delete()
+        pass
diff --git a/csunplugged/tests/BaseTestWithDB.py b/csunplugged/tests/BaseTestWithDB.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/BaseTestWithDB.py
@@ -0,0 +1,52 @@
+"""Base test class with methods implemented for Django testing."""
+
+from django.test import TestCase
+from django.contrib.auth.models import User
+from django.test.client import Client
+from django.utils.translation import activate
+
+
+class BaseTestWithDB(TestCase):
+    """Base test class with methods implemented for Django testing."""
+
+    def __init__(self, *args, **kwargs):
+        """Create a BaseTestWithDB object."""
+        super().__init__(*args, **kwargs)
+        self.language = None
+
+    @classmethod
+    def setUpTestData(cls):
+        """Create data for the whole class.
+
+        Creates a new user.
+        """
+        super(BaseTestWithDB, cls).setUpTestData()
+        cls.username = 'test'
+        cls.email = 'test@test.com'
+        cls.password = 'test'
+        cls.test_user = User.objects.create_user(cls.username, cls.email, cls.password)
+
+    @classmethod
+    def setUpClass(cls):
+        """Automatically called before tests in class."""
+        super(BaseTestWithDB, cls).setUpClass()
+        cls.client = Client()
+
+    @classmethod
+    def tearDownClass(cls):
+        """Automatically called after tests in class."""
+        super(BaseTestWithDB, cls).tearDownClass()
+
+    def setUp(self):
+        """Automatically called before each test.
+
+        Sets the language if specified, logs into the database
+        """
+        if self.language is not None:
+            activate(self.language)
+        login = self.client.login(username=self.username, password=self.password)
+        self.assertEqual(login, True)
+
+    def tearDown(self):
+        """Automatically called after each test. Deletes the user."""
+        pass
diff --git a/csunplugged/tests/general/__init__.py b/csunplugged/tests/general/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/general/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the general application."""
diff --git a/csunplugged/tests/general/templatetags/__init__.py b/csunplugged/tests/general/templatetags/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/general/templatetags/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the template tags in the general application."""
diff --git a/csunplugged/tests/general/templatetags/test_render_html_field.py b/csunplugged/tests/general/templatetags/test_render_html_field.py
new file mode 100644
diff --git a/csunplugged/tests/general/urls/__init__.py b/csunplugged/tests/general/urls/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/general/urls/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the URL routing in the general application."""
diff --git a/csunplugged/tests/general/urls/test_about.py b/csunplugged/tests/general/urls/test_about.py
new file mode 100644
diff --git a/csunplugged/tests/general/urls/test_home.py b/csunplugged/tests/general/urls/test_home.py
new file mode 100644
diff --git a/csunplugged/tests/general/views/__init__.py b/csunplugged/tests/general/views/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/general/views/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the views in the general application."""
diff --git a/csunplugged/tests/general/views/test_general_about_view.py b/csunplugged/tests/general/views/test_general_about_view.py
new file mode 100644
diff --git a/csunplugged/tests/general/views/test_general_index_view.py b/csunplugged/tests/general/views/test_general_index_view.py
new file mode 100644
diff --git a/csunplugged/tests/resources/__init__.py b/csunplugged/tests/resources/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/resources/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the resources application."""
diff --git a/csunplugged/tests/resources/models/__init__.py b/csunplugged/tests/resources/models/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/resources/models/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the models in the resources application."""
diff --git a/csunplugged/tests/resources/models/test_resource.py b/csunplugged/tests/resources/models/test_resource.py
new file mode 100644
diff --git a/csunplugged/tests/resources/resource/__init__.py b/csunplugged/tests/resources/resource/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/resources/resource/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the resources in the resources application."""
diff --git a/csunplugged/tests/resources/resource/test_sorting_network.py b/csunplugged/tests/resources/resource/test_sorting_network.py
new file mode 100644
diff --git a/csunplugged/tests/resources/resource/test_treasure_hunt.py b/csunplugged/tests/resources/resource/test_treasure_hunt.py
new file mode 100644
diff --git a/csunplugged/tests/resources/urls/__init__.py b/csunplugged/tests/resources/urls/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/resources/urls/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the URL routing in the resources application."""
diff --git a/csunplugged/tests/resources/urls/test_generate.py b/csunplugged/tests/resources/urls/test_generate.py
new file mode 100644
diff --git a/csunplugged/tests/resources/urls/test_index.py b/csunplugged/tests/resources/urls/test_index.py
new file mode 100644
diff --git a/csunplugged/tests/resources/urls/test_resource.py b/csunplugged/tests/resources/urls/test_resource.py
new file mode 100644
diff --git a/csunplugged/tests/resources/views/__init__.py b/csunplugged/tests/resources/views/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/resources/views/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the views in the resources application."""
diff --git a/csunplugged/tests/resources/views/test_index_view.py b/csunplugged/tests/resources/views/test_index_view.py
new file mode 100644
diff --git a/csunplugged/tests/resources/views/test_view_methods.py b/csunplugged/tests/resources/views/test_view_methods.py
new file mode 100644
diff --git a/csunplugged/tests/topics/__init__.py b/csunplugged/tests/topics/__init__.py
--- a/csunplugged/tests/topics/__init__.py
+++ b/csunplugged/tests/topics/__init__.py
@@ -1 +1 @@
-"""Module for testing topics application."""
+"""Module for tests of the topics application."""
diff --git a/csunplugged/tests/topics/models/__init__.py b/csunplugged/tests/topics/models/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the models in the topics application."""
diff --git a/csunplugged/tests/topics/models/test_connected_generated_resource.py b/csunplugged/tests/topics/models/test_connected_generated_resource.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_connected_generated_resource.py
@@ -0,0 +1,22 @@
+from model_mommy import mommy
+from tests.BaseTestWithDB import BaseTestWithDB
+from topics.models import ConnectedGeneratedResource
+from topics.models import Lesson
+from resources.models import Resource
+
+
+class ConnectedGeneratedResourceModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+    def test_connected_generated_resource(self):
+        resource = mommy.make(Resource)
+        lesson = mommy.make(Lesson)
+        new_resource = ConnectedGeneratedResource.objects.create(
+            resource=resource,
+            lesson=lesson,
+            description='this is a description'
+        )
+        query_result = ConnectedGeneratedResource.objects.get(resource=resource, lesson=lesson)
+        self.assertEqual(query_result, new_resource)
diff --git a/csunplugged/tests/topics/models/test_curriculum_area.py b/csunplugged/tests/topics/models/test_curriculum_area.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_curriculum_area.py
@@ -0,0 +1,16 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from topics.models import CurriculumArea
+
+
+class CurriculumAreaModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+    def test_curriculum_area(self):
+        new_curriculum_area = CurriculumArea.objects.create(
+            slug='slug',
+            name='name',
+        )
+        query_result = CurriculumArea.objects.get(slug='slug')
+        self.assertEqual(query_result, new_curriculum_area)
diff --git a/csunplugged/tests/topics/models/test_curriculum_integration.py b/csunplugged/tests/topics/models/test_curriculum_integration.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_curriculum_integration.py
@@ -0,0 +1,40 @@
+from model_mommy import mommy
+from tests.BaseTestWithDB import BaseTestWithDB
+from topics.models import CurriculumIntegration
+from topics.models import Topic
+from topics.models import CurriculumArea
+from topics.models import Lesson
+
+
+class CurriculumIntegrationModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+    def test_curriculum_integration(self):
+        # Setup Auxliary Data
+        topic = mommy.make(Topic)
+        curriculum_area = mommy.make(
+            CurriculumArea,
+            make_m2m=True,
+            name='cats'
+        )
+        prerequisite_lesson = mommy.make(
+            Lesson,
+            make_m2m=True,
+            name='dogs'
+        )
+
+        # Test
+        new_curriculum_integration = CurriculumIntegration.objects.create(
+            topic=topic,
+            slug='slug',
+            number=1,
+            name='name',
+            content='content'
+        )
+        new_curriculum_integration.curriculum_areas.add(curriculum_area)
+        new_curriculum_integration.prerequisite_lessons.add(prerequisite_lesson)
+
+        query_result = CurriculumIntegration.objects.get(slug='slug')
+        self.assertEqual(query_result, new_curriculum_integration)
diff --git a/csunplugged/tests/topics/models/test_learning_outcome.py b/csunplugged/tests/topics/models/test_learning_outcome.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_learning_outcome.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class LearningOutcomeModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_lesson.py b/csunplugged/tests/topics/models/test_lesson.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_lesson.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class LessonModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_programming_exercise.py b/csunplugged/tests/topics/models/test_programming_exercise.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_programming_exercise.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class ProgrammingExerciseModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_programming_exercise_difficulty.py b/csunplugged/tests/topics/models/test_programming_exercise_difficulty.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_programming_exercise_difficulty.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class ProgrammingExerciseDifficultyModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_programming_exercise_language.py b/csunplugged/tests/topics/models/test_programming_exercise_language.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_programming_exercise_language.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class ProgrammingExerciseLanguageModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_programming_exercise_language_implementation.py b/csunplugged/tests/topics/models/test_programming_exercise_language_implementation.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_programming_exercise_language_implementation.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class ProgrammingExerciseLanguageImplementationModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/models/test_topic.py b/csunplugged/tests/topics/models/test_topic.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_topic.py
@@ -0,0 +1,19 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from topics.models import Topic
+
+
+class TopicModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+    def test_topic(self):
+        new_topic = Topic.objects.create(
+            slug='binary-numbers',
+            name='Binary Numbers',
+            content='content',
+            other_resources='content',
+            icon='icon'
+        )
+        query_result = Topic.objects.get(name='Binary Numbers')
+        self.assertEqual(query_result, new_topic)
diff --git a/csunplugged/tests/topics/models/test_unit_plan.py b/csunplugged/tests/topics/models/test_unit_plan.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/models/test_unit_plan.py
@@ -0,0 +1,7 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+
+
+class UnitPlanModelTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
diff --git a/csunplugged/tests/topics/test_models.py b/csunplugged/tests/topics/test_models.py
deleted file mode 100644
--- a/csunplugged/tests/topics/test_models.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from tests.BaseTest import BaseTest
-from topics.models import Topic
-
-
-class ModelTest(BaseTest):
-
-    def __init__(self, *args, **kwargs):
-        BaseTest.__init__(self, *args, **kwargs)
-
-    def test_topic_str(self):
-        new_topic = Topic(
-            slug='binary-numbers',
-            name='Binary Numbers',
-            content='content',
-            other_resources='content',
-            icon='icon'
-        )
-        self.assertEqual(new_topic.__str__(), 'Binary Numbers')
diff --git a/csunplugged/tests/topics/test_urls.py b/csunplugged/tests/topics/test_urls.py
deleted file mode 100644
--- a/csunplugged/tests/topics/test_urls.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from tests.BaseTest import BaseTest
-from django.urls import reverse
-
-
-class UrlsTest(BaseTest):
-
-    def __init__(self, *args, **kwargs):
-        BaseTest.__init__(self, *args, **kwargs)
-
-    def test_topics_index(self):
-        url = reverse('topics:index')
-        self.assertEqual(url, '/en/topics/')
-        response = self.client.get(url)
-        self.assertEqual(200, response.status_code)
-
-    def test_topic(self):
-        url = reverse('topics:topic', args=['binary-numbers'])
-        self.assertEqual(url, '/en/topics/binary-numbers/')
-
-        # response = self.client.get(url)
-        # self.assertEqual(200, response.status_code)
-
-    def test_missing_topic(self):
-        pass
-        # url = reverse('topics:topic')
-        # response = self.client.get(url)
-        # self.assertEqual(404, response.status_code)
-
-    def test_activity(self):
-        pass
-
-    def test_other_resources(self):
-        pass
-
-    def test_plugged_in(self):
-        pass
-
-    def test_prog_ex(self):
-        pass
-
-    def test_prog_ex_solution(self):
-        pass
-
-    def test_unit_plan(self):
-        pass
-
-    def test_lesson(self):
-        pass
-
-    def test_difficulty(self):
-        pass
diff --git a/csunplugged/tests/topics/urls/__init__.py b/csunplugged/tests/topics/urls/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the URL routing in the topics application."""
diff --git a/csunplugged/tests/topics/urls/test_all_curriculum_integrations.py b/csunplugged/tests/topics/urls/test_all_curriculum_integrations.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_all_curriculum_integrations.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class AllCurriculumIntegrationsURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_curriculum_integration(self):
+        url = reverse('topics:all_curriculum_integrations')
+        self.assertEqual(url, '/en/topics/curriculum-integrations/')
diff --git a/csunplugged/tests/topics/urls/test_index.py b/csunplugged/tests/topics/urls/test_index.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_index.py
@@ -0,0 +1,16 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class IndexURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_index(self):
+        url = reverse('topics:index')
+        self.assertEqual(url, '/en/topics/')
+
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
diff --git a/csunplugged/tests/topics/urls/test_integration.py b/csunplugged/tests/topics/urls/test_integration.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_integration.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class IntegrationURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_integration(self):
+        url = reverse('topics:integration', args=['binary-numbers', 'binary-bracelets'])
+        self.assertEqual(url, '/en/topics/binary-numbers/integrations/binary-bracelets/')
diff --git a/csunplugged/tests/topics/urls/test_integration_list.py b/csunplugged/tests/topics/urls/test_integration_list.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_integration_list.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class IntegrationListURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_integration_list(self):
+        url = reverse('topics:integration_list', args=['binary-numbers'])
+        self.assertEqual(url, '/en/topics/binary-numbers/integrations/')
diff --git a/csunplugged/tests/topics/urls/test_lesson.py b/csunplugged/tests/topics/urls/test_lesson.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_lesson.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class LessonURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_lesson(self):
+        url = reverse('topics:lesson', args=['binary-numbers', 'unit-plan', 'lesson-1'])
+        self.assertEqual(url, '/en/topics/binary-numbers/unit-plan/lesson/lesson-1/')
diff --git a/csunplugged/tests/topics/urls/test_other_resources.py b/csunplugged/tests/topics/urls/test_other_resources.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_other_resources.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class OtherResourcesURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_other_resources(self):
+        url = reverse('topics:other_resources', args=['binary-numbers'])
+        self.assertEqual(url, '/en/topics/binary-numbers/other-resources/')
diff --git a/csunplugged/tests/topics/urls/test_programming_exercise.py b/csunplugged/tests/topics/urls/test_programming_exercise.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_programming_exercise.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class ProgrammingExerciseURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_programming_exercise(self):
+        url = reverse('topics:programming_exercise', args=['binary-numbers', 'unit-plan', 'lesson-1', 'exercise-1'])
+        self.assertEqual(url, '/en/topics/binary-numbers/unit-plan/lesson/lesson-1/plugged-in/exercise-1')
diff --git a/csunplugged/tests/topics/urls/test_programming_exercise_difficulty.py b/csunplugged/tests/topics/urls/test_programming_exercise_difficulty.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_programming_exercise_difficulty.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class ProgrammingExerciseDifficultyURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_programming_exercise_difficulty(self):
+        url = reverse('topics:programming_exercise_difficulty', args=['1'])
+        self.assertEqual(url, '/en/topics/plugged-in/difficulty/1')
diff --git a/csunplugged/tests/topics/urls/test_programming_exercise_language_solution.py b/csunplugged/tests/topics/urls/test_programming_exercise_language_solution.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_programming_exercise_language_solution.py
@@ -0,0 +1,15 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class ProgrammingExerciseLanguageSolutionURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_programming_exercise_language_solution(self):
+        args = ['binary-numbers', 'unit-plan', 'lesson-1', 'exercise-1', 'python']
+        url = reverse('topics:programming_exercise_language_solution', args=args)
+        expected_url = '/en/topics/binary-numbers/unit-plan/lesson/lesson-1/plugged-in/exercise-1/python-solution'
+        self.assertEqual(url, expected_url)
diff --git a/csunplugged/tests/topics/urls/test_programming_exercises_list.py b/csunplugged/tests/topics/urls/test_programming_exercises_list.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_programming_exercises_list.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class ProgrammingExercisesListURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_programming_exercises_list(self):
+        url = reverse('topics:programming_exercises_list', args=['binary-numbers', 'unit-plan', 'lesson-1'])
+        self.assertEqual(url, '/en/topics/binary-numbers/unit-plan/lesson/lesson-1/plugged-in/')
diff --git a/csunplugged/tests/topics/urls/test_topic.py b/csunplugged/tests/topics/urls/test_topic.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_topic.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class TopicURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_topic(self):
+        url = reverse('topics:topic', args=['binary-numbers'])
+        self.assertEqual(url, '/en/topics/binary-numbers/')
diff --git a/csunplugged/tests/topics/urls/test_unit_plan.py b/csunplugged/tests/topics/urls/test_unit_plan.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/urls/test_unit_plan.py
@@ -0,0 +1,13 @@
+from tests.BaseTestWithDB import BaseTestWithDB
+from django.urls import reverse
+
+
+class UnitPlanURLTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
+
+    def test_valid_unit_plan(self):
+        url = reverse('topics:unit_plan', args=['binary-numbers', 'unit-plan'])
+        self.assertEqual(url, '/en/topics/binary-numbers/unit-plan/')
diff --git a/csunplugged/tests/topics/views/__init__.py b/csunplugged/tests/topics/views/__init__.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/views/__init__.py
@@ -0,0 +1 @@
+"""Module for tests of the views in the topics application."""
diff --git a/csunplugged/tests/topics/views/test_all_curriculum_integration_list.py b/csunplugged/tests/topics/views/test_all_curriculum_integration_list.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_curriculum_integration_list.py b/csunplugged/tests/topics/views/test_curriculum_integration_list.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_curriculum_integration_view.py b/csunplugged/tests/topics/views/test_curriculum_integration_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/test_views.py b/csunplugged/tests/topics/views/test_index_view.py
similarity index 83%
rename from csunplugged/tests/topics/test_views.py
rename to csunplugged/tests/topics/views/test_index_view.py
--- a/csunplugged/tests/topics/test_views.py
+++ b/csunplugged/tests/topics/views/test_index_view.py
@@ -1,12 +1,13 @@
-from tests.BaseTest import BaseTest
+from tests.BaseTestWithDB import BaseTestWithDB
 from django.urls import reverse
 from topics.models import Topic
 
 
-class IndexViewTest(BaseTest):
+class IndexViewTest(BaseTestWithDB):
 
     def __init__(self, *args, **kwargs):
-        BaseTest.__init__(self, *args, **kwargs)
+        super().__init__(*args, **kwargs)
+        self.language = 'en'
 
     def test_index_with_no_topics(self):
         url = reverse('topics:index')
@@ -22,6 +23,7 @@ def test_index_with_one_topic(self):
             icon='icon'
         )
         new_topic.save()
+
         url = reverse('topics:index')
         response = self.client.get(url)
         self.assertEqual(200, response.status_code)
diff --git a/csunplugged/tests/topics/views/test_lesson_view.py b/csunplugged/tests/topics/views/test_lesson_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_other_resources_view.py b/csunplugged/tests/topics/views/test_other_resources_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_programming_exercise_difficulty.py b/csunplugged/tests/topics/views/test_programming_exercise_difficulty.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_programming_exercise_language_solution_view.py b/csunplugged/tests/topics/views/test_programming_exercise_language_solution_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_programming_exercise_list.py b/csunplugged/tests/topics/views/test_programming_exercise_list.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_programming_exercise_view.py b/csunplugged/tests/topics/views/test_programming_exercise_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_topic_view.py b/csunplugged/tests/topics/views/test_topic_view.py
new file mode 100644
diff --git a/csunplugged/tests/topics/views/test_unit_plan_view.py b/csunplugged/tests/topics/views/test_unit_plan_view.py
new file mode 100644
diff --git a/docs/source/developer/test_suite.rst b/docs/source/developer/test_suite.rst
new file mode 100644
--- /dev/null
+++ b/docs/source/developer/test_suite.rst
@@ -0,0 +1,36 @@
+The Test Suite
+##############################################################################
+
+.. contents:: Contents
+  :local:
+
+Structure
+==============================================================================
+
+.. code-block:: none
+
+  └── tests/
+      ├── general/
+      │   ├── templatetags/
+      │   ├── urls/
+      │   ├── views/
+      │   ├── test_models.py
+      │   ├── test_urls.py
+      │   └── test_views.py
+      ├── resources/
+      │   ├── models/
+      │   ├── resource/
+      │   ├── urls/
+      │   ├── views/
+      │   ├── test_models.py
+      │   ├── test_urls.py
+      │   └── test_views.py
+      ├── topics/
+      │   ├── models/
+      │   ├── urls/
+      │   ├── views/
+      │   ├── test_models.py
+      │   ├── test_urls.py
+      │   └── test_views.py
+      └── BaseTest.py
+
diff --git a/requirements/test.txt b/requirements/test.txt
--- a/requirements/test.txt
+++ b/requirements/test.txt
@@ -1,4 +1,11 @@
 # Test dependencies
 
+# Check Python style
 flake8==3.3.0
 pydocstyle==2.0.0
+
+#Coverage Tools
+coverage==4.0.3
+
+# Mock Database
+model_mommy==1.3.2