Як знущатися над користувачами та запитами в django


75

У мене є код django, який взаємодіє з об’єктами запиту або об’єктами користувача. Наприклад, щось на зразок:

foo_model_instance = models.get_or_create_foo_from_user(request.user)

Якби ви збиралися тестувати за допомогою оболонки django python або в unittest, що б ви там передали? Тут просто буде працювати об'єкт User, але потреба в об'єкті фіктивного запиту також часто виникає.

Для оболонки або для модульних тестів:

  • Як ви глузуєте з користувачів?
  • Як ви глузуєте над запитами?

2
"Ви продовжуєте використовувати це слово, але я не думаю, що воно означає те, що ви думаєте, що означає ..." Я думаю, ви маєте на увазі "макет".
Mike DeSimone

9
@Mike: Це звучить смішно, але я думаю, що він це правильно зробив. @pax: Побий мене до перфомансу :(
mpen

6
Я ... мушу визнати, що ... в тиші моєї кімнати ... пізно ввечері ... я ... так, так! Я глузую над користувачами! Усі! @perrierism: ми не глузуємо з вас, ми просто насолоджуємось вашим чудовим вибором слів.
Пітер Роуелл

Відповіді:


84

Для запиту я б використав RequestFactory, що входить до складу Django.

from django.test.client import RequestFactory
rf = RequestFactory()
get_request = rf.get('/hello/')
post_request = rf.post('/submit/', {'foo': 'bar'})

для користувачів я б використовував django.contrib.auth.models.User як @ozan запропонував і, можливо, з фабричним хлопчиком для швидкості (із фабричним хлопчиком ви можете вибрати не зберігати в БД)


1
Це, безумовно, правильна відповідь зараз, коли RequestFactory доступний. З повагою до відповіді Озана (що створення реальних об’єктів є достатнім і бажаним). Я не використовував Factory Boy, але якщо це наближається до якості Rail Factory Factory Girl, здається, це буде чудовим вибором.
Перрелл,

Найкраще рішення, яке працювало для мене в сценарії міграції django. Однак поточну версію потрібно request.userвстановити. Крім того, щоб використовувати цей запит як звичайний вигляд, приємно мати request.csrf_processing_done = Trueготовий запит (для проходження перевірок CSRF)
garmoncheg

51

Як ви глузуєте з користувачів?

Ініціалізація django.contrib.auth.models.Userоб’єкта. User.objects.create_userполегшує це.

Як ви глузуєте над запитами?

Ініціалізація django.http.HttpRequestоб’єкта.

Звичайно, є ярлики залежно від того, що ви хочете зробити. Якщо вам просто потрібен об’єкт з userатрибутом, який вказує на користувача, просто створіть щось (що завгодно) і надайте йому цей атрибут.


2
@ S.Lott - це добре іноді використовувати справжню річ, але це закінчується дуже повільно, коли ваш проект росте. Приємно мати пробні тести, які ви можете виконати за кілька секунд, а не за кілька хвилин.
ТМ.

1
@ TM: Можливо, це взагалі так. Але клієнт Django дійсно швидкий. Чи є у вас якась альтернатива та деякі орієнтири, щоб показати економію часу?
S.Lott

@ S.Lott просто досвід роботи з моїми власними проектами. Альтернативою використанню вбудованого користувача є просто використання чогось на зразок фреймворку pymox або створення власних макетних об’єктів з тим самим API, як було запропоновано в декількох відповідях тут. Використання реальних об'єктів запиту не є проблемою швидкості.
ТМ.

11
@ S.Lott Я не кажу, що клієнт працює повільно, або стверджує, що знущання швидші за клієнта (я припускаю, що під "клієнтом" ви маєте на увазі фіктивний веб-браузер djangos). Я кажу, що вони швидші за доступ до БД (що стосується лише Userчастини цього запитання). Якщо ви не думаєте, що знущання швидші, ніж насправді доступ до БД, то я підозрюю, що ви насправді не пробували і не порівнювали. У дуже маленькому проекті наша команда перейшла від тестового набору, який зайняв 1,5 хвилини до <5 секунд, коли ми змінили код, щоб висміяти моделі. Не потрібно писати еталон, коли розрив такий великий.
ТМ.

1
Мої реальні запити мають .userатрибут. Екземпляри django.http.HttpRequestцього не роблять. Я просто встановлюю request.user після його створення. Це здається розумним?
Джонатан Хартлі

7

Ви можете або власноруч висміювати, як запропонував Анураг Уніял, або скористатися насмішкуванням.

У відповідь на тих, хто каже, що ви можете просто створити звичайного користувача, як би це було в будь-якому випадку в Django ... Я б запропонував, що це перешкоджає точці модульного тесту. Модульний тест не повинен торкатися бази даних, але створивши користувача, ви змінили базу даних, отже, чому ми хотіли б знущатись над нею.


2
Як згадував Даніель, тест-драйвер створює, а потім знищує для вас тестову базу даних, тому вам не потрібно турбуватися про це.
ozan

4
За винятком випадків, коли ви використовуєте базу даних, це більше не є модульним тестом. Можливо, це все ще цілком дійсний інтеграційний тест, але це не модульний тест.
Michael Williamson

1
Проблема в тому, що створення та знищення бази даних вимагає часу. Я хочу врешті-решт пройти тисячі тестів у мить ока, щоразу, коли вношу зміни. Я не хочу підтримувати базу даних та екземпляр програми, щоб запускати мої тести.
Тім Оттінгер

Погоджено, дуже корисно мати тести, які не потрапляють у БД. Навіть якщо ви використовуєте базу даних SQLite, вона все одно працює повільніше, ніж тести, які використовують макети.
ТМ.

6

Прочитайте про макетні об’єкти тут
http://en.wikipedia.org/wiki/Mock_object
http://www.mockobjects.com/

І використовуйте цю бібліотеку python для знущання над користувачем
http://python-mock.sourceforge.net/

в іншому випадку ви можете написати простий клас користувача самостійно, використовуйте це як вихідну точку

class MockUser(object):
    def __call__(self, *args, **kwargs):
        return self

    def __getattr__(Self, name):
        return self

додати конкретні випадки тощо тощо


5

Вам не потрібно глузувати з користувачів, оскільки ви можете просто створити його в рамках тесту - база даних знищується після закінчення тесту.

Щоб знущатися над запитами, використовуйте цей фрагмент від Саймона Віллісона.


Хоча я погоджуюсь, ви зазвичай можете уникнути створення користувачів для своїх тестів - бувають випадки, коли ви цього не хочете - або це не входить до компетенції тесту. Якщо я тестую, що дозвіл відмовлено, якщо допоміжний метод повертає False - я неправильно підключаю це до бази даних. Цей допоміжний метод існує, Оскільки я не хочу знати про представлення бази даних.
yarbelk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.