Ключевые assert-методы

Главные assert-методы TestCase и когда каждый из них уместен.

Assert-метод — метод TestCase, который проверяет одно условие и роняет тест с понятным сообщением, если условие не выполнено.

Почему не просто assert

Можно писать assert a == b, но методы TestCase дают лучшую диагностику: вместо сухого «AssertionError» вы видите оба значения. assertEqual(2, 3) напечатает 2 != 3, а голый assert 2 == 3 — ничего полезного.

Самые ходовые методы

МетодПроходит, если
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) истинно
assertFalse(x)bool(x) ложно
assertIn(a, b)a in b
assertIsNone(x)x is None
assertAlmostEqual(a, b)a и b близки (для float)
assertRaises(Err)вызов поднял исключение Err

Запускаемый пример с разными методами

import unittest

def normalize(name):
    return name.strip().lower()

class TestAsserts(unittest.TestCase):
    def test_equal(self):
        self.assertEqual(normalize("  Анна "), "анна")

    def test_truthy(self):
        self.assertTrue("анна")          # непустая строка истинна
        self.assertFalse("")             # пустая строка ложна

    def test_membership(self):
        self.assertIn("a", "anna")
        self.assertNotIn("z", "anna")

    def test_identity(self):
        self.assertIsNone(None)
        self.assertIsNotNone(0)          # 0 не None!

unittest.main(argv=[''], exit=False, verbosity=2)

Вывод:

test_equal (__main__.TestAsserts.test_equal) ... ok
test_identity (__main__.TestAsserts.test_identity) ... ok
test_membership (__main__.TestAsserts.test_membership) ... ok
test_truthy (__main__.TestAsserts.test_truthy) ... ok

----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

assertAlmostEqual — для чисел с плавающей точкой

Числа float нельзя сравнивать на точное равенство: 0.1 + 0.2 не равно ровно 0.3. Для этого есть assertAlmostEqual, который сравнивает с точностью до знаков:

import unittest

class TestFloat(unittest.TestCase):
    def test_naive_fails(self):
        # 0.1 + 0.2 == 0.30000000000000004 — НЕ ровно 0.3
        self.assertNotEqual(0.1 + 0.2, 0.3)

    def test_almost(self):
        # А так — корректно: близко с точностью по умолчанию (7 знаков)
        self.assertAlmostEqual(0.1 + 0.2, 0.3)

    def test_places(self):
        self.assertAlmostEqual(3.14159, 3.14, places=2)

unittest.main(argv=[''], exit=False, verbosity=2)

Вывод:

test_almost (__main__.TestFloat.test_almost) ... ok
test_naive_fails (__main__.TestFloat.test_naive_fails) ... ok
test_places (__main__.TestFloat.test_places) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Правило: любые float сравнивайте через assertAlmostEqual, иначе тест будет случайно падать из-за погрешности.

Сравнение коллекций

Для списков и словарей assertEqual работает «из коробки» и красиво показывает разницу. Есть и специальные методы: assertListEqual, assertDictEqual, assertCountEqual (равенство без учёта порядка элементов).

import unittest

class TestCollections(unittest.TestCase):
    def test_list(self):
        self.assertEqual([1, 2, 3], [1, 2, 3])

    def test_order_independent(self):
        # Одинаковые элементы, разный порядок
        self.assertCountEqual([3, 1, 2], [1, 2, 3])

    def test_dict(self):
        self.assertEqual({"a": 1, "b": 2}, {"b": 2, "a": 1})

unittest.main(argv=[''], exit=False, verbosity=2)

Вывод:

test_dict (__main__.TestCollections.test_dict) ... ok
test_list (__main__.TestCollections.test_list) ... ok
test_order_independent (__main__.TestCollections.test_order_independent) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

assertTrue против assertEqual: тонкий момент

Соблазнительно всё проверять через assertTrue: self.assertTrue(a == b). Но так делать не стоит. Если такая проверка упадёт, вы увидите лишь сухое «False is not true» — без значений a и b. А assertEqual(a, b) при провале покажет оба значения и их разницу. Правило: используйте самый конкретный подходящий метод. Для равенства — assertEqual, для вхождения — assertIn, для NoneassertIsNone. assertTrue/assertFalse оставляйте для настоящих булевых проверок, где значение и так очевидно.

assertIs против assertEqual

Ещё пара, которую путают. assertEqual проверяет равенство значений (через ==), а assertIsтождество объектов (через is, тот же объект в памяти). В большинстве тестов вам нужен assertEqual. assertIs уместен в особых случаях: проверить, что функция вернула именно None, тот самый синглтон или конкретный закэшированный объект. Для None есть отдельный удобный assertIsNone, который читается яснее, чем assertIs(x, None).

Итог

  • Методы TestCase дают понятную диагностику — предпочитайте их голому assert.
  • Базовый набор: assertEqual, assertTrue/False, assertIn, assertIsNone.
  • Для float — только assertAlmostEqual, не assertEqual.
  • assertCountEqual сравнивает коллекции без учёта порядка.
Проверьте себя
1. Почему assertEqual(2, 3) лучше голого assert 2 == 3?
AОн работает быстрее
BОн показывает оба значения в сообщении (2 != 3) — лучше диагностика
Cassert вообще не работает в тестах
DРазницы нет
2. Каким методом сравнивать числа с плавающей точкой?
AassertEqual
BassertAlmostEqual
CassertTrue
DassertIs
3. Что проверяет assertCountEqual(a, b)?
AЧто длины равны
BЧто коллекции содержат одинаковые элементы независимо от порядка
CЧто a и b — один объект
DЧто b пустой
Поддержать проект