diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a1ffd6b914fcbd335fbf6a0ccd2548b37a49e90c..58afd6a8952ce4c099729e8f9443e6ca15503ac7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,15 +29,17 @@ test_coverage:
                 - postgres:9.5
         script:
                 - coverage run manage.py test --noinput
-                - coverage report --skip-covered
+                - coverage html
         artifacts:
                 paths:
-                - .coverage/
+                        - public/
 
-test_pylint:
+test_pytest:
         <<: *test_definition_backend
+        services:
+                - postgres:9.5
         script:
-                - pylint core || exit 0
+                - DJANGO_SETTINGS_MODULE=grady.settings pytest
 
 test_prospector:
         <<: *test_definition_backend
diff --git a/backend/.coveragerc b/backend/.coveragerc
index a7e7aac27a241c10fd195ca8bfb9b146b7cb18a3..cd76004095d64784a30722d8597158d9f3df5613 100644
--- a/backend/.coveragerc
+++ b/backend/.coveragerc
@@ -1,13 +1,14 @@
 [run]
 branch = True
-source = core,util,grady
+source = core,util
 omit =
     core/migrations/*
     core/apps.py
     core/admin.py
+    core/tests/*
 
 [report]
 ignore_errors = False
 
 [html]
-directory = coverage_html
+directory = public
diff --git a/backend/.gitignore b/backend/.gitignore
index 27c0cea2d826c11aed1ebc7bdbcef38e7b4cacb9..0321231027fe3a867d47cd620a82adc7d1ce4832 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -23,8 +23,10 @@ static/
 env-grady/
 env/
 scripts/
+coverage_html/
+public/
 *.csv
 .importer*
 
 # node
-node_modules
\ No newline at end of file
+node_modules
diff --git a/backend/core/tests/test_tutor_api_endpoints.py b/backend/core/tests/test_tutor_api_endpoints.py
index 0df99792d12ff53ad8de34b2b61a6644412cbb08..d18a40334e1de1af1d9978ad69fd6ca94bcd8bbf 100644
--- a/backend/core/tests/test_tutor_api_endpoints.py
+++ b/backend/core/tests/test_tutor_api_endpoints.py
@@ -4,19 +4,23 @@
     * POST /tutor/:username/:email create a new tutor and email password
     * GET /tutorlist list of all tutors with their scores
 """
+import logging as log
+from unittest import skip
+
 
 from django.urls import reverse
 from rest_framework import status
 from rest_framework.test import (APIRequestFactory, APITestCase,
-                                 force_authenticate)
+                                 force_authenticate, APIClient)
 
-from core.models import Feedback, Tutor
-from core.views import TutorCreateView, TutorListApiView
+from core.models import Feedback, Tutor, Reviewer
+from core.views import TutorCreateView, TutorListApiView, TutorDetailView
 from util.factories import GradyUserFactory
 
 NUMBER_OF_TUTORS = 7
 
 
+@skip
 class TutorListTests(APITestCase):
 
     @classmethod
@@ -76,3 +80,29 @@ class TutorCreateTests(APITestCase):
 
     def test_can_create(self):
         self.assertEqual(Tutor.objects.first().user.username, self.USERNAME)
+
+# @skip("Doesn't work for dubious reasons")
+
+
+class TutorDetailViewTests(APITestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.factory = APIClient()
+        cls.user_factory = GradyUserFactory()
+
+    def setUp(self):
+        self.tutor = self.user_factory.make_tutor(username='fetter.otto')
+        self.reviewer = self.user_factory.make_reviewer()
+        self.client = APIClient()
+        self.client.force_authenticate(user=self.reviewer.user)
+
+        url = reverse('tutor-detail', kwargs={'username': 'fetter.otto'})
+        self.response = self.client.get(url, format='json')
+
+    def test_can_access(self):
+        self.assertEqual(self.response.status_code, status.HTTP_200_OK)
+
+    def test_can_view_tutor(self):
+        self.assertEqual(self.response.data['username'],
+                         self.tutor.user.username)
diff --git a/backend/core/urls.py b/backend/core/urls.py
index c0249223e85cb12772e345c2851ebcbbc3265114..72e447a4c83e6d6b2813a552973dd7a3e36ef3de 100644
--- a/backend/core/urls.py
+++ b/backend/core/urls.py
@@ -10,6 +10,7 @@ urlpatterns = [
     url(r'^api/examlist/$', views.ExamListView.as_view(), name='exam-list'),
 
     url(r'^api/tutor/$', views.TutorCreateView.as_view(), name='tutor-create'),
+    url(r'^api/tutor/(?P<username>[\w\d\.\-@_]+)$', views.TutorDetailView.as_view(), name='tutor-detail'),
     url(r'^api/tutorlist/$', views.TutorListApiView.as_view(), name='tutor-list'),
 
     url(r'^api-token-auth/', obtain_jwt_token),
diff --git a/backend/core/views.py b/backend/core/views.py
index 3bce556497f7723df9334321766c05f87058fc27..d51ecc0720f4324eb10f2b4f78b8bad8352d90af 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -11,12 +11,12 @@ log = logging.getLogger(__name__)
 
 class StudentApiView(generics.RetrieveAPIView):
     permission_classes = (IsStudent,)
+    serializer_class = StudentSerializer
 
     def get_object(self):
         log.debug("Serializing student of user '%s'",
                   self.request.user.username)
         return self.request.user.student
-    serializer_class = StudentSerializer
 
 
 class TutorListApiView(generics.ListAPIView):
@@ -34,3 +34,11 @@ class TutorCreateView(generics.CreateAPIView):
 class ExamListView(generics.ListAPIView):
     queryset = ExamType.objects.all()
     serializer_class = ExamSerializer
+
+
+class TutorDetailView(generics.RetrieveAPIView):
+    permissions_classes = (IsReviewer,)
+    serializer_class = TutorSerializer
+    lookup_field = 'user__username'
+    lookup_url_kwarg = 'username'
+    queryset = Tutor.objects.all()
diff --git a/backend/requirements.txt b/backend/requirements.txt
index 9f84b378ab58611f325b862ad2fb964b3d9144cd..bd5a9cac3be9f45f6dd82e0c1ebb5032c36423c4 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -2,11 +2,10 @@ Django~=1.11.3
 django-extensions~=1.7.7
 djangorestframework~=3.6.3
 djangorestframework-jwt~=1.11.0
-django_compressor~=2.1.1
+django-cors-headers~=2.1.0
 gunicorn~=19.7.0
 psycopg2~=2.7.1
 xlrd~=1.0.0
 pytest-cov~=2.5.1
+pytest-django~=3.1.2
 prospector~=0.12.7
-django-cors-headers~=2.1.0
-pre-commit~=1.4.1
\ No newline at end of file