Заказ тестов Юнитест - PullRequest
       7

Заказ тестов Юнитест

39 голосов
/ 04 ноября 2010

Как я могу быть уверен в порядке методов unittest? Правильный ли алфавитный или цифровой префикс?

class TestFoo(TestCase):
    def test_1(self):
        ...
    def test_2(self):
        ...

или

class TestFoo(TestCase):
    def test_a(self):
        ...
    def test_b(self):
        ...

Ответы [ 17 ]

72 голосов
/ 07 ноября 2012

Нет никаких оснований считать, что вы не можете опираться на то, что было сделано в предыдущем тесте, или должны восстановить его с нуля для следующего теста. По крайней мере, обычно не предлагается никаких причин, но вместо этого люди просто уверенно говорят: «Не надо». Это не полезно.

В общем, я устала читать здесь слишком много ответов, в которых, в основном, говорится: «Вы не должны этого делать», вместо того, чтобы давать какую-либо информацию о том, как лучше всего это сделать, если по мнению спрашивающих есть веская причина для этого. Если бы я хотел чье-то мнение о том, должен ли я что-то сделать, я бы попросил мнение о том, является ли это хорошей идеей.

Это не так, если вы прочитаете, скажем, loadTestsFromTestCase и то, что он вызывает, то в конечном итоге сканирует методы с каким-то шаблоном имени в любом порядке, в котором они встречаются в словаре методов классов, в основном в порядке ключей. Он берет эту информацию и создает тестовый набор для сопоставления ее с классом TestCase. Предоставление списка, упорядоченного по вашему желанию, является одним из способов сделать это. Я не уверен в самом эффективном / самом чистом способе сделать это, но это работает.

65 голосов
/ 11 марта 2014

Вы можете отключить его, установив sortTestMethodsUsing в None: http://docs.python.org/2/library/unittest.html#unittest.TestLoader.sortTestMethodsUsing

Для чистых юнит-тестов вы, ребята, правы; но для тестов компонентов и интеграционных тестов ... Я не согласен с тем, что вы не должны предполагать ничего о государстве. Что делать, если вы проверяете состояние. Например, ваш тест подтверждает, что служба автоматически запускается после установки. Если при настройке вы запускаете службу, затем делаете утверждение, то вы больше не проверяете состояние, а проверяете функциональность «запуска службы».

Еще один пример - когда ваша установка занимает много времени или занимает много места, и часто запускать ее становится нецелесообразно.

Многие разработчики, как правило, используют "unittest" фреймворки для тестирования компонентов ... поэтому остановитесь и спросите себя, я занимаюсь тестированием модулей или тестированием компонентов.

12 голосов
/ 27 октября 2011

Если вы используете 'nose' и пишете свои тестовые случаи как функции (а не как методы какого-либо производного класса TestCase), 'nose' не влияет на порядок, а использует порядок функций, определенный вфайл.Для того, чтобы методы assert_ * были удобны без необходимости создавать подклассы TestCase, я обычно использую модуль тестирования из numpy.Пример:

from numpy.testing import *

def test_aaa():
    assert_equal(1, 1)

def test_zzz():
    assert_equal(1, 1)

def test_bbb():
    assert_equal(1, 1)

Выполнение этого с '' nosetest -vv '' дает:

test_it.test_aaa ... ok
test_it.test_zzz ... ok
test_it.test_bbb ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.050s
OK

Примечание для всех тех, кто утверждает, что модульные тесты не должны заказываться: пока этоПравда, модульные тесты должны быть изолированными и могут выполняться независимо, ваши функции и классы обычно не являются независимыми.Они скорее строятся на другом - от более простых / низкоуровневых функций до более сложных / высокоуровневых функций.Когда вы начинаете оптимизировать свои низкоуровневые функции и путаетесь (со своей стороны, я делаю это часто; если вы этого не делаете, вам, вероятно, все равно не нужен модульный тест ;-), тогда это намного лучше для диагностики причины,когда сначала идут тесты для простых функций, а позже - для функций, которые зависят от этих функций.Если тесты отсортированы в алфавитном порядке, истинная причина обычно тонет среди ста неудачных утверждений, которых нет, потому что у тестируемой функции есть ошибка, а потому, что у функции низкого уровня, на которую она опирается, есть.

почему я хочу, чтобы мои модульные тесты сортировались так, как я их указал: не использовать состояние, созданное в ранних тестах в последующих тестах, а как очень полезный инструмент для диагностики проблем.

11 голосов
/ 04 ноября 2010

Зачем вам нужен конкретный тестовый заказ?Тесты должны быть изолированными, и поэтому должна быть возможность запускать их в любом порядке или даже параллельно.

Если вам нужно протестировать что-то вроде отписки пользователя, тест может создать новую базу данных с тестовой подпиской.а потом попробуй отписаться.У этого сценария есть свои проблемы, но, в конце концов, это лучше, чем тесты, зависящие друг от друга.(Обратите внимание, что вы можете выделить общий тестовый код, чтобы вам не приходилось повторять код установки БД или создавать данные тестирования до тошноты.)

8 голосов
/ 16 августа 2012

Я наполовину согласен с идеей, что тесты нельзя заказывать.В некоторых случаях это помогает (черт побери!) Располагать их по порядку ... в конце концов, это и есть причина для 'unit' в UnitTest.

При этом одна из альтернатив - использовать фиктивные объекты для макетаи исправьте элементы, которые должны быть запущены до того тестируемого кода.Вы также можете добавить туда фиктивную функцию, чтобы обезьяна исправила ваш код.Для получения дополнительной информации ознакомьтесь с Mock, который сейчас является частью стандартной библиотеки. Mock

Вот несколько видео YouTube, если вы ранее не использовали Mock.

Видео 1

Видео 2

Видео 3

Более конкретно, попробуйте использовать методы класса для структурирования кода, затем поместите все методы класса в один основной метод тестирования..

import unittest
import sqlite3

class MyOrderedTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.create_db()
        cls.setup_draft()
        cls.draft_one()
        cls.draft_two()
        cls.draft_three()

    @classmethod
    def create_db(cls):
        cls.conn = sqlite3.connect(":memory:")

    @classmethod
    def setup_draft(cls):
        cls.conn.execute("CREATE TABLE players ('draftid' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'first', 'last')")

    @classmethod
    def draft_one(cls):
        player = ("Hakeem", "Olajuwon")
        cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)

    @classmethod
    def draft_two(cls):
        player = ("Sam", "Bowie")
        cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)

    @classmethod
    def draft_three(cls):
        player = ("Michael", "Jordan")
        cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)

    def test_unordered_one(self):
        cur = self.conn.execute("SELECT * from players")
        draft = [(1, u'Hakeem', u'Olajuwon'), (2, u'Sam', u'Bowie'), (3, u'Michael', u'Jordan')]
        query = cur.fetchall()
        print query
        self.assertListEqual(query, draft)

    def test_unordered_two(self):
        cur = self.conn.execute("SELECT first, last FROM players WHERE draftid=3")
        result = cur.fetchone()
        third = " ".join(result)
        print third
        self.assertEqual(third, "Michael Jordan")
7 голосов
/ 04 ноября 2010

Не полагайтесь на заказ. Если они используют какое-то общее состояние, такое как файловая система или база данных, вам следует создать методы setUp и tearDown, которые приведут вашу среду в тестируемое состояние, а затем очистить после выполнения тестов. Каждый тест должен предполагать, что среда соответствует определению в setUp, и не должен делать никаких дополнительных предположений.

6 голосов
/ 07 февраля 2013

Хорошо, может быть немного позже, но в любом случае ...

Вы должны попробовать хоботок библиотека.Это позволит вам сделать заказ тестов, а также настроить любые тестовые зависимости.Я использую его, и эта библиотека действительно потрясающая.

Например, если test case #1 от module A должно зависеть от test case #3 от module B you CAN установить это поведение с помощью библиотеки.

6 голосов
/ 02 мая 2011

Существует ряд причин для определения приоритетов тестов, не в последнюю очередь это производительность, на которую ориентируется JUnit Max. Иногда полезно хранить очень медленные тесты в их собственном модуле, чтобы вы могли быстро получить отзывы о тех тестах, которые не страдают от таких же тяжелых зависимостей. Порядок также полезен для отслеживания сбоев в тестах, которые не являются полностью автономными.

4 голосов
/ 26 августа 2015

http://docs.python.org/library/unittest.html

Обратите внимание, что порядок, в котором будут выполняться различные тестовые примеры, определяется путем сортировки имен тестовых функций относительно встроенного порядка строк.

Если вам нужно явно установить порядок, используйте монолитный тест.

class Monolithic(TestCase):
  def step1(self):
      ...

  def step2(self):
      ...

  def steps(self):
    for name in sorted(dir(self)):
      if name.startswith("step"):
        yield name, getattr(self, name) 

  def test_steps(self):
    for name, step in self.steps():
      try:
        step()
      except Exception as e:
        self.fail("{} failed ({}: {})".format(step, type(e), e)

Проверьте сообщение для деталей.

4 голосов
/ 15 мая 2012

Существуют сценарии, в которых порядок может быть важен, и где setUp и Teardown входят как ограниченные. Есть только один метод setUp и tearDown, который логичен, но вы можете поместить в них столько информации, пока не станет ясно, что на самом деле могут делать setUp или tearDown.

Возьмем этот интеграционный тест в качестве примера:

Вы пишете тесты, чтобы проверить, правильно ли работают форма регистрации и форма входа. В таком случае важен порядок, так как вы не можете войти без существующего аккаунта. Что еще более важно, порядок ваших тестов представляет собой своего рода взаимодействие с пользователем. Где каждый тест может представлять собой шаг во всем тестируемом процессе или потоке.

Разделение вашего кода на эти логические части имеет несколько преимуществ.

Возможно, это не лучшее решение, но я часто использую один метод, который запускает реальные тесты.

def test_registration_login_flow(self):
    _test_registration_flow()
    _test_login_flow()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...