0

I'm running tests in a Django project called lucy-web. If I run a simple python manage.py test, all tests pass:

(venv) Kurts-MacBook-Pro:lucy-web kurtpeek$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
........................
----------------------------------------------------------------------
Ran 24 tests in 22.097s

OK
Destroying test database for alias 'default'...

However, if I try to run a particular test defined in lucy_web/tests/test_schedule_request.py, it fails:

(venv) Kurts-MacBook-Pro:lucy-web kurtpeek$ python manage.py test lucy_web.tests.test_schedule_request
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.F
======================================================================
FAIL: test_send_schedule_request (lucy_web.tests.test_schedule_request.ScheduleRequestTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/Dev/lucy/lucy-web/venv/lib/python3.6/site-packages/freezegun/api.py", line 495, in wrapper
    result = func(*args, **kwargs)
  File "/Users/kurtpeek/Documents/Dev/lucy/lucy-web/lucy_web/tests/test_schedule_request.py", line 44, in test_send_schedule_request
    self.assertEqual(mail.outbox[0].body, expected_body)
AssertionError: 'Hi!\[17 chars]ily 1) wants to schedule a Birth Preparation a[102 chars] AM.' != 'Hi!\[17 chars]ily 12) wants to schedule a Birth Preparation [103 chars] AM.'
  Hi!

- Test Test (family 1) wants to schedule a Birth Preparation and Preferences session within the next day or two.
+ Test Test (family 12) wants to schedule a Birth Preparation and Preferences session within the next day or two.
?                    +

  Test requested this session on 01/01/12 at 09:00 AM.

----------------------------------------------------------------------
Ran 2 tests in 2.365s

FAILED (failures=1)
Destroying test database for alias 'default'...

Here is the offending test as defined in test_schedule_request.py:

import json

from django.conf import settings
from django.contrib.auth.models import User
from django.core import mail
from django.test import Client, TestCase
from freezegun import freeze_time

from ..models import Company, Family, Package, SessionType, Session, SessionCategory

class ScheduleRequestTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = '/api/v1.0/sessions/send_schedule_request/'

    @freeze_time("2012-01-01 17:00:00")
    def test_send_schedule_request(self):
        user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
        user.first_name = "Test"
        user.last_name = "Test"
        user.save()
        company = Company.objects.create(name='test company')
        package = Package.objects.create(name='test package', company=company)
        family = Family.objects.create(employee_user=user, employee_first_name='Test', employee_last_name='test', employee_email='test@test.net', package=package, point_of_contact='Employee')
        category = SessionCategory.objects.create(name="Birth Prep")
        session_type = SessionType.objects.create(category=category, title='Birth Preparation and Preferences', recommended_timing='32-36 weeks', min_duration=60, max_duration=90, allow_virtual=True, allow_in_person=True, description='some stuff', what_to_expect='other stuff')
        session = Session.objects.create(session_number=1, family=family, session_type=session_type, location=Session.OTHER, other_location='spa', feedback_expert='YES', feedback_session='YES')
        self.client.login(username='john', password='johnpassword')
        response = self.client.post(self.url, json.dumps({'session_id': session.id, 'timeframe': 'within the next day or two'}), content_type="application/json")
        self.assertEqual(response.status_code, 200)

        # Check that session status has been updated
        self.assertEqual(Session.objects.filter(id=session.id)[0].status, 'Times Requested')

        # Check that two emails have been sent.
        self.assertEqual(len(mail.outbox), 2)

        # Verify that the contents of the emails are correct
        self.assertEqual(mail.outbox[0].subject, 'LUCY: Request to Schedule Session')
        self.assertEqual(mail.outbox[0].from_email, settings.DEFAULT_FROM_EMAIL)
        self.assertEqual(mail.outbox[0].to, [settings.CUSTOMER_SERVICE_EMAIL])
        self.assertEqual(mail.outbox[0].reply_to, [user.email])
        expected_body = "Hi!\n\nTest Test (family 12) wants to schedule a Birth Preparation and Preferences session within the next day or two.\n\nTest requested this session on 01/01/12 at 09:00 AM."
        self.assertEqual(mail.outbox[0].body, expected_body)

        self.assertEqual(mail.outbox[1].subject, 'LUCY: Request to Schedule Session')
        self.assertEqual(mail.outbox[1].from_email, settings.DEFAULT_FROM_EMAIL)
        self.assertEqual(mail.outbox[1].to, [user.email])
        self.assertEqual(mail.outbox[1].reply_to, [settings.CUSTOMER_SERVICE_EMAIL])
        expected_body = "Hi Test,\n\nWe received your request for Birth Preparation and Preferences and our team is currently working on scheduling it for you. We will confirm the expert, date & time within 48 hours (or sooner if your request was urgent) via this email address.\n\nIf you have any questions, simply reply to this email and someone from our team will get back to you ASAP!\n\nBest,\nLUCY team"
        self.assertEqual(mail.outbox[1].body, expected_body)

I've checked using the --verbosity option that this test was run successfully when I was running all tests. The only explanation I can think of is that the tests are somehow not isolated from each other, and the success of one depends on the setUp of the other.

Could this be the case? Do I perhaps have to write some tearDown methods in the previous test cases? Or does Django run each test on a new database, so that this should not be necessary?

Kurt Peek
  • 52,165
  • 91
  • 301
  • 526
  • 1
    Looks like you don't clean up properly after each test and your tests expect that already. In this particular case it expects 11 families to be there before the test. – Klaus D. Jan 19 '18 at 02:46
  • Indeed, I should probably implement `tearDown` methods to accompany the `setUp` ones as stated in the answer to this related question: https://stackoverflow.com/questions/20481804/django-unit-tests-failing-when-run-with-other-test-cases – Kurt Peek Jan 19 '18 at 18:03

1 Answers1

2

It appears that the code that created the expected_body refers to the an id or other similar field. If the full test suite is run it will keep using the next unique number when it creates the test (in the full suite it will be the 12th creation).

When running the test by itself it is therefore the 1st creation.

You should refer to the id when creating the string e.g.:

expected_body = "Hi!\n\nTest Test (family %s) wants to schedule a Birth Preparation and Preferences session within the next day or two.\n\nTest requested this session on 01/01/12 at 09:00 AM." % family.id
Stuart Dines
  • 748
  • 6
  • 12