Show pytest warnings with CLI flag
Aug 8, 2016
3 minutes read

If you are migrating from unittest to pytest, you might encounter warnings when running your tests. No failures, no errors, but pytest-warnings. This may be confusing to you, regardless of whether you are new to pytest or an experienced user.


Pytest

In the following example, pytest displays pytest-warnings at the very end of the test run in the session summary.

$ py.test
=========================== test session starts ============================
platform darwin -- Python 3.5.0, pytest-2.8.7, py-1.4.31, pluggy-0.3.1
collected 2 items

test_foobar.py ..

=============== 2 passed, 1 pytest-warnings in 0.02 seconds ================

Unittest

Running the same tests under unittest does not show any warnings.

$ python -m unittest
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Tests

As you can see there are two tests that are collected and both pass without any failures or errors.

Let’s have a look at the code:

# -*- coding: utf-8 -*-

import unittest


class Client:
    def get(self, url, *args, **kwargs):
        # Send a real request based on the given parameters
        pass


class TestResponse:
    def __init__(self, method, url, *args, **kwargs):
        if 'foobar' in url:
            self.status = 404
            self.reason = 'foobar'
        else:
            self.status = 200
            self.reason = None


class TestClient(Client):
    def get(self, url, *args, **kwargs):
        return TestResponse('get', url)


class TestScrapingTool(unittest.TestCase):
    def setUp(self):
        self.client = TestClient()

    def test_success(self):
        response = self.client.get('https://github.com/pytest-dev')
        self.assertEqual(response.status, 200)
        self.assertEqual(response.reason, None)

    def test_failure(self):
        response = self.client.get('foobar')
        self.assertEqual(response.status, 404)
        self.assertEqual(response.reason, 'foobar')

At first glance, the implementation may look just fine (albeit admittedly not particularly meaningful). It implements a stub client that inherits from a real client and returns a TestResponse instance as opposed to sending a request over a network connection.

Then there are two unittest tests, one for a valid url and another one for an invalid url respectively. Pytest is perfectly fine with it being unittest.TestCase methods, so that is unlikely to cause the issue.


Warnings

Pytest comes with a -rw command line flag to display internal warnings, such as the one that is reported for our test session:

$ py.test -rw
=========================== test session starts ============================
platform darwin -- Python 3.5.0, pytest-2.8.7, py-1.4.31, pluggy-0.3.1
collected 2 items

test_foobar.py ..

========================== pytest-warning summary ==========================
WC1 /show_pytest_warnings/test_foobar.py cannot collect test class
'TestResponse' because it has a __init__ constructor
=============== 2 passed, 1 pytest-warnings in 0.02 seconds ================

Running the suite with this flag now points us to the source of the problem. Pytest tries to collect TestResponse as its name matches the naming conventions for test classes. However it finds a __init__ method, which it cannot understand.


Solution

In this particular case, there is an simple solution to what one could consider a code smell: Rename the classes which are used in your tests but not actual test cases.

class StubResponse:
    ...


class StubClient(Client):
    ...

Reporting Options

For more information about the various reporting options, please consult the help via $ py.test --help and see the according section:

-r chars              show extra test summary info as specified by chars
                      (f)ailed, (E)error, (s)skipped, (x)failed, (X)passed
                      (w)pytest-warnings (a)all.

Back to posts