2

I am trying to write unit-test to my create function in Django project. This is my first experience creating of unit-tests. Why I cant create new data? From error I understand that there is no articles in test database. Where I did mistake?

tests.py:

class ArticleViewTestCase(TestCase):
    def setUp(self):
        self.user = User.objects.create(
            username='user',
            email='user@gmail.com',
            password='password'
        )
        self.client = Client()
    
    def test_article_create(self):
        self.assertTrue(self.user)
        self.client.login(username='user', password='password')
        response = self.client.get('/article/create/')
        self.assertEquals(response.status_code, 200)

        with open('/home/nurzhan/Downloads/planet.jpg', 'rb') as image:
            imageStringIO = StringIO(image.read()) # <-- ERROR HERE

        response = self.client.post(
            '/article/create/',
            content_type='multipart/form-data',
            data={
                'head': 'TEST',
                'opt_head': 'TEST',
                'body': 'TEST',
                'location': 1,
                'public': True,
                'idx': 0,
                'image': (imageStringIO, 'image.jpg')
            },
            follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual(Article.objects.all().count(), 1)

ERROR:

Traceback (most recent call last):
  File "/home/nurzhan/CA/article/tests.py", line 26, in test_article_create
    imageStringIO = StringIO(image.read())
TypeError: 'module' object is not callable
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
Nurzhan Nogerbek
  • 4,806
  • 16
  • 87
  • 193

3 Answers3

2

You can override form_invalid and check it data in your test

class ArticleCreateView(CreateView):
    # YOUR code here

   def form_invalid(self, form):
        data = {'status': False, 'errors': form.errors}
        return JsonResponse(data, , status=500)

in test method:

with open('/home/nurzhan/Downloads/planet.jpg', 'rb') as image:
    response = self.client.post('/article/create/',
        data={
            'head': 'TEST',
            'opt_head': 'TEST',
            'body': 'TEST',
            'location': 1,
            'public': True,
            'idx': 0,
            'image': image
        },
        follow=True, format='multipart'
     )
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
  • This code raise error: `AssertionError: 500 != 200` in line `self.assertEqual(response.status_code, 200)` after post response. Do you have ideas about that? – Nurzhan Nogerbek Sep 12 '17 at 09:31
  • 1
    you need to look on response `errors` and fix it. or simple add `print form.errors` and look on it in console. – Brown Bear Sep 12 '17 at 09:34
  • Well in console I notice this: `
    • image
      • Required field.
    `. It seems like data to image field is not correct. `'image': 'article/images/2017/09/11/planet.jpg'` Is this code correct?
    – Nurzhan Nogerbek Sep 12 '17 at 09:41
  • now you find error, but why this data not correct, you need talk with your coder, because looks fine and i can not to invalidate why you get the error, i think you need inspect your `CustomClearableFileInput` widget – Brown Bear Sep 12 '17 at 09:45
1

When unit testing, Django empties the database at the end of each test, so each test starts with an empty database. It is very likely that no user exists at the beginning of your test, which means login is failing. You should change the test to something like this:

from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User

class ArticleViewTestCase(TestCase):

    def test_article_create(self):
        User.objects.create(username='alice', password=make_password('topsecret'))
        logged_in = self.client.login(username='alice', password="topsecret")
        self.assertTrue(logged_in)
        # Continue your test here

After you get a grip on that, you will eventually want to move the user creation to the setUp() method.

Antonis Christofides
  • 6,990
  • 2
  • 39
  • 57
  • Your code raise error like: `AssertionError: False is not true` in line: `self.assertTrue(logged_in)`. Do you have any ideas about that? – Nurzhan Nogerbek Sep 12 '17 at 07:01
  • Exactly. You need to create a user before attempting to login. – Antonis Christofides Sep 12 '17 at 08:17
  • I use this code: `User.objects.create(username='user', email='user@gmail.com', password="password")` But unfortunately I steal has this error: `AssertionError: False is not true` in line `self.assertTrue(logged_in)`. How create user correctly? – Nurzhan Nogerbek Sep 12 '17 at 08:28
0

Insert to your test code PDB test tool:

# Below response = self.client.get('/article/create/')
import pdb;pdb.set_trace()

And check response.data there will be answer for you what is going on there :)

Some tips to your test code:

If u don't need check user login data then use self.client.force_login(self.user) you need give only user objects and its clear. differents U can split get and post to different test methods its good when u have a lot of https methods to test but its optional - only suggest

Try don't use len() on your objects from db just use Article.objects.all().count() to get numbers of objects then u dont need use len().

articles_amount = Article.objects.all().count()
self.assertEqual(articles_amount, 1)
Thaian
  • 1,215
  • 2
  • 20
  • 30
  • Your code raise this error: `AssertionError: > != 1` in line: `self.assertEqual(articles_amount, 1)`. Also if I use `self.client.force_login(self.user)` Django say that `AttributeError: 'ArticleViewTestCase' object has no attribute 'user'`. Do you have any ideas about that? – Nurzhan Nogerbek Sep 12 '17 at 07:47
  • Yes u need provide user objects for example `self.user = User.objects.get(id=1)` or if u use factory just assign factory and use in `self.client.force_login(self.user)`. Yes i made mistake and forgot add `count()` its a method. – Thaian Sep 12 '17 at 07:53