Django self.client.login (…) không hoạt động trong các bài kiểm tra đơn vị


83

Tôi đã tạo người dùng cho các bài kiểm tra đơn vị của mình theo hai cách:

1) Tạo một vật cố định cho "auth.user" giống như sau:

    { 
        "pk": 1, 
        "model": "auth.user", 
        "fields": { 
            "username": "homer", 
            "is_active": 1, 
            "password": 
"sha1$72cd3$4935449e2cd7efb8b3723fb9958fe3bb100a30f2", 
            ... 
        } 
    }

Tôi đã bỏ đi những phần dường như không quan trọng.

2) Sử dụng 'create_user' trong hàm setUp (mặc dù tôi muốn giữ mọi thứ trong lớp fixtures của mình):

def setUp(self): 
       User.objects.create_user('homer', 'ho...@simpson.net', 'simpson') 

Lưu ý rằng mật khẩu là simpson trong cả hai trường hợp.

Tôi đã xác minh rằng thông tin này đang được tải chính xác vào cơ sở dữ liệu thử nghiệm hết lần này đến lần khác. Tôi có thể lấy đối tượng Người dùng bằng cách sử dụng User.objects.get. Tôi có thể xác minh mật khẩu là chính xác bằng cách sử dụng 'check_password.' Người dùng đang hoạt động.

Tuy nhiên, luôn luôn, self.client.login (username = 'homer', password = 'simpson') THẤT BẠI. Tôi bối rối không biết tại sao. Tôi nghĩ rằng tôi đã đọc mọi cuộc thảo luận trên Internet liên quan đến điều này. Ai có thể giúp đỡ?

Mã đăng nhập trong bài kiểm tra đơn vị của tôi trông giống như sau:

    login = self.client.login(username='homer', password='simpson') 
    self.assertTrue(login) 

Cảm ơn.


1
Thông báo lỗi bạn nhận được là gì?
zs2020,

Trường hợp kiểm tra không thành công trên dòng, 'self.assertTrue (đăng nhập)'; hàm login () trả về False.
thebossman

1
Về cơ bản, tôi đã sao chép và dán biến thể thứ 2 của bạn và nó hoạt động trên Django 1.3. Bạn có thể đăng toàn bộ mã bao gồm cả nhập khẩu không?
Liorsion

Điều này đã bị chôn vùi ở đâu đó trong một cơ sở mã mà tôi không còn truy cập được nữa. Nếu tôi gặp vấn đề, tôi chắc chắn sẽ theo dõi, nhưng đối với bản ghi, đó là với phiên bản Django trước đó; Tôi nghĩ 1.0.2.
thebossman,

Câu trả lời:


120

Mã không hoạt động:

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

user = User.objects.create(username='testuser', password='12345')

c = Client()
logged_in = c.login(username='testuser', password='12345')

Tại sao nó không hoạt động?

Trong đoạn mã trên, khi User được tạo, hàm băm mật khẩu thực được đặt thành 12345. Khi máy khách gọi loginphương thức, giá trị của passwordđối số 12345, được chuyển qua hàm băm, dẫn đến một cái gì đó như

hash('12345') = 'adkfh5lkad438....'

Sau đó, giá trị này được so sánh với mã băm được lưu trữ trong cơ sở dữ liệu và máy khách bị từ chối truy cập vì 'adkfh5lkad438....' != '12345'

Giải pháp

Điều thích hợp cần làm là gọi set_passwordhàm, chuyển chuỗi đã cho qua hàm băm và lưu trữ kết quả vào User.password.

Ngoài ra, sau khi gọi set_passwordchúng ta phải lưu Userđối tượng cập nhật vào cơ sở dữ liệu:

user = User.objects.create(username='testuser')
user.set_password('12345')
user.save()

c = Client()
logged_in = c.login(username='testuser', password='12345')

44
Bạn sử dụng User.objects.create_superuser()User.objects.create_user()thực hiện chính xác set_password()cuộc gọi này .
vdboor

như thế nào về việc khi nào bạn đăng nhập một người ở
gấu trúc đá

để thêm vào bình luận @vdboor: lưu ý rằng vì Django 1.4 cũng User.objects.get_or_create()thực hiện set_password()cuộc gọi được yêu cầu
furins

51

Một cách dễ dàng hơn là sử dụng force_login, tính năng mới trong Django 1.9.

force_login(user, backend=None)

Ví dụ:

class LoginView(TestCase):
    def setUp(self):
        self.client.force_login(User.objects.get_or_create(username='testuser')[0])

5

Bạn có thể kiểm tra như dưới đây,

from django.test import TransactionTestCase, Client

class UserHistoryTest(TransactionTestCase):
    self.user = User.objects.create(username='admin', password='pass@123', email='admin@admin.com')
    self.client = Client() # May be you have missed this line

    def test_history(self):
        self.client.login(username=self.user.username, password='pass@123')
        # get_history function having login_required decorator
        response = self.client.post(reverse('get_history'), {'user_id': self.user.id})
        self.assertEqual(response.status_code, 200)

Trường hợp thử nghiệm này đã làm việc cho tôi.


5

Kiểm tra django.contrib.sessionsđược thêm vào INSTALLED_APPSclient.login()kiểm tra rằng nó đúng và sẽ luôn trả về false nếu nó không phải là:

https://docs.djangoproject.com/es/1.9/topics/http/sessions/#enabling-sessions


2
+1 cho điều này. Ngay cả với django.contrib.sessions.middleware.SessionMiddlewarecác lỗi phần mềm trung gian, bạn vẫn không thể đăng nhập qua django.test.Client. Tôi mất một tuần để tìm ra câu trả lời này
học sinh

0
from django.test import TestCase
from django.contrib.auth.models import User
from django.test import Client
class MyProfile(TestCase):
    @classmethod
    def setUpClass(self):
        self.username = 'dummy' + data + '@gmail.com'
        self.password = 'Dummy@123'
        user = User.objects.create(username=self.username)
        user.set_password(self.password)
        user.save()
        c = Client()
        self.client_object = c.login(username=self.username, password=self.password)
        self.content_type = "application/json"
        response = self.client_object.post('/api/my-profile/', content_type=self.content_type)

-3

Nếu ai đó vẫn theo dõi điều này, tôi nghĩ rằng các thuộc tính 'is_staff' và 'is_active' nên được giữ True để đăng nhập thành công ......

self.user = User.objects.create(username='testuser',password='pwd',is_active=1,is_staff=1)


4
Điều này vừa hoạt động ........... self.user = User.objects.create (username = 'testuser', password = '12345', is_active = True, is_staff = True, is_superuser = True). user.set_password ('hello') self.user.save () user = authenticate (username = 'testuser', password = 'hello') login = self.c.login (username = 'testuser', password = 'hello' ) self.assertTrue (đăng nhập)
Arindam Roychowdhury 14/11/12

Điều này không liên quan gì đến việc is_staffxác định khi nào quyền truy cập vào bảng quản trị nói chung được cấp. Như bạn có thể thấy dữ liệu trong bài đăng ban đầu đã có is_active = 1và đó cũng là mặc định cho User.objects.create().
jnns

1
@arindamroychowdhury - Wow, mà thực sự làm việc .. (Cảm nhận của bạn, đó là)
Richard de Wit

1
Nó có thể là một vấn đề về phiên bản, nhưng tôi đã phải bình luận về cuộc gọi xác thực của bạn. Ngoài ra, bình luận của bạn hoạt động như một nhà vô địch! Khi thử nghiệm thêm, tôi thấy rằng is_active, is_superuser và is_staff đều không cần thiết. Điều đã thực hiện đó là lệnh gọi set_password.
dolphus333
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.