如何修复单元测试中的错误? |断言错误

Posted

技术标签:

【中文标题】如何修复单元测试中的错误? |断言错误【英文标题】:How fix error in unit test? | AssertionError 【发布时间】:2018-02-20 09:43:20 【问题描述】:

我正在尝试在 Django 项目中将unit-test 写入我的create function。这是我第一次创建单元测试的经验。为什么我不能创建新数据?从错误中我了解到测试数据库中没有文章。我哪里做错了?

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)

错误:

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

【问题讨论】:

默认reposne创建返回201状态,看看你的回复,为什么是200 你的意思是我需要使用self.assertEquals(response.status_code, 201) 是的,你是对的 在控制台中我注意到post method 返回200。看:[12/Sep/2017 06:36:07] "POST /article/create/ HTTP/1.1" 200 1866 所以我认为 200 状态是正确的。最后2行有问题。你对此有什么想法吗? 有时200 状态返回错误消息。 【参考方案1】:

您可以覆盖form_invalid 并在您的测试中检查它的数据

class ArticleCreateView(CreateView):
    # YOUR code here

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

在测试方法中:

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'
     )

【讨论】:

此代码在发布响应后引发错误:AssertionError: 500 != 200 in line self.assertEqual(response.status_code, 200)。你对此有什么想法吗? 您需要查看回复errors 并修复它。或简单添加print form.errors 并在控制台中查看。 在控制台中我注意到了这一点:&lt;ul class="errorlist"&gt;&lt;li&gt;image&lt;ul class="errorlist"&gt;&lt;li&gt;Required field.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;。似乎图像字段的数据不正确。 'image': 'article/images/2017/09/11/planet.jpg'这段代码正确吗? 现在你发现了错误,但是为什么这个数据不正确,你需要和你的编码员谈谈,因为看起来很好,我不能使你得到错误的原因无效,我认为你需要检查你的 @987654330 @小部件【参考方案2】:

当单元测试时,Django 在每次测试结束时清空数据库,因此每次测试都从一个空数据库开始。在您的测试开始时很可能没有用户存在,这意味着登录失败。你应该把测试改成这样:

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

在掌握了这一点之后,您最终会希望将用户创建移至 setUp() 方法。

【讨论】:

您的代码引发错误,例如:AssertionError: False is not true in line:self.assertTrue(logged_in)。你对此有什么想法吗? 没错。您需要在尝试登录之前创建一个用户。 我使用这个代码:User.objects.create(username='user', email='user@gmail.com', password="password") 但不幸的是我偷了这个错误:AssertionError: False is not true in line self.assertTrue(logged_in)。如何正确创建用户?【参考方案3】:

插入您的测试代码 PDB 测试工具:

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

并检查response.data 将会为您解答那里发生的事情:)

测试代码的一些提示:

如果您不需要检查用户登录数据,请使用 self.client.force_login(self.user) 你只需要给用户对象和它的清晰。 不同之处 当您有很多 https 方法要测试但它是可选的时,您可以将 get 和 post 拆分到不同的测试方法,这很好 - 仅建议

尽量不要在来自 db 的对象上使用 len() 只需使用 Article.objects.all().count() 获取对象数量 那么你不需要使用len()

articles_amount = Article.objects.all().count()
self.assertEqual(articles_amount, 1)

【讨论】:

您的代码会引发此错误:AssertionError: &lt;bound method MultilingualQuerySet.count of &lt;MultilingualQuerySet []&gt;&gt; != 1 in line:self.assertEqual(articles_amount, 1)。另外,如果我使用self.client.force_login(self.user) Django 说AttributeError: 'ArticleViewTestCase' object has no attribute 'user'。你对此有什么想法吗? 是的,您需要提供用户对象,例如self.user = User.objects.get(id=1),或者如果您使用工厂,只需分配工厂并在self.client.force_login(self.user) 中使用。是的,我犯了错误,忘记添加count() 这是一种方法。

以上是关于如何修复单元测试中的错误? |断言错误的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 单元测试显示完全错误

如何在 JEST 单元测试中修复“SVG 未定义”

如何修复 @testable 导入无法在 xcode 单元测试中加载模块

错误:超过 2000 毫秒的超时。带有承诺的单元测试

Spring MVC -- 应用测试

如何使用线程执行单元测试? [复制]