how to write django test meant to fail?

DjangoTestingTdd

Django Problem Overview


I have a model called Thing with an attribute called name, and I want name to be a char field that's only 3 characters long.

How do I write a test for that?

class TestCase1(TestCase):
    def test1(self):
        thing = Thing(name='1234')

that test should fail. How do I properly write the test so that the test passes when that object fails?

Django Solutions


Solution 1 - Django

If you're expecting Thing(name='1234') to raise an exception, there are two ways to deal with this.

One is to use Django's assertRaises (actually from unittest/unittest2):

def mytest(self):
    self.assertRaises(FooException, Thing, name='1234')

This fails unless Thing(name='1234') raises a FooException error. Another way is to catch the expected exception and raise one if it doesn't happen, like this:

def mytest(self):
    try:
        thing = Thing(name='1234')
        self.fail("your message here")
    except FooException:
        pass
    

Obviously, replace the FooException with the one you expect to get from creating the object with too long a string. ValidationError?

A third option (as of Python 2.7) is to use assertRaises as a context manager, which makes for cleaner, more readable code:

def mytest(self):
    with self.assertRaises(FooException):
        thing = Thing(name='1234')

Sadly, this doesn't allow for custom test failure messages, so document your tests well. See https://hg.python.org/cpython/file/2.7/Lib/unittest/case.py#l97 for more details.

Solution 2 - Django

I am currently using the expectedFailure decorator from unittest. That works as advertised: Fails when there is no error, passes when there is a failure.

I use expectedFailure to verify that my custom assert-routines actually work and not just rubberstamp everything OK.

import unittest
from django.test import TestCase

class EmojiTestCase(TestCase):
    
    @unittest.expectedFailure
    def testCustomAssert(self):
        self.assertHappyFace(':(') # must fail.

But prints a warning-message during testing. I use it with Django and Nose. Which others have seen, too.

> /usr/lib64/python3.4/unittest/case.py:525: RuntimeWarning: TestResult has no addExpectedFailure method, reporting as passes RuntimeWarning)

I came here to find a better solution, but found none. So I at least wanted to tell others that come what I've been working with.

Solution 3 - Django

In my previous project i had to do something like test driven development, so i have written some test case which must catch certain types of error. If it don't gets the error then i have messed up something. Here i share my code.

from django.test import TestCase
from django.contrib.auth.models import User

class ModelTest(TestCase):

def test_create_user_with_email(self):

	with self.assertRaises(TypeError):
		email = "[email protected]"
		password = 'testpass1'

		user = User.objects.create_user(
			email = email,
			password = password,)

		self.assertEqual(user.email, email)
		self.assertTrue(user.check_password(password))

You can see i have tried to create a user with email and password but default Django user model need "username" and "password" arguments to create user. So here my testcase must raise "TypeError". And that what i tried to do here.

Solution 4 - Django

Something like this should work:

thing = Thing.objects.create(name='1234')  
# not sure if you need here .get() or if. create() truncates the field on its own
self.assertEqual(thing.name, '123') # or: self.assertEqual(len(thing.name), 3)

-- but such test looks weird :-)

Also, note that MySQLdb backend will raise Warning exception to notify you of truncating the string, so you might want to check it with assertRaises.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexander BirdView Question on Stackoverflow
Solution 1 - DjangoGDornView Answer on Stackoverflow
Solution 2 - DjangoChrisView Answer on Stackoverflow
Solution 3 - DjangoAyemun Hossain AshikView Answer on Stackoverflow
Solution 4 - DjangoTomasz ZielińskiView Answer on Stackoverflow