question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Stop using unittest's addCleanup

See original GitHub issue

We want to stop using the unittest compatibility mode of pytest because:

  • the current code does not work with pytest>=4.2 (possibly a bug in pytest)
  • it’s better to use only one test framework, and pytest is nice 😃

The pure pytest migration has started in https://github.com/urllib3/urllib3/pull/1614 where @RatanShreshtha has worked on transforming all self.assert* calls into Python asserts. This was an important first part because that was the majority of unittest code.

Most of the remaining changes will now be quite limited in scope, but there’s one thing left that I would like to talk about here: the self.addCleanup calls. We have about 150 of them, and they ensure that the opened connections are closed. self.addCleanup is called on the following five classes:

  • HTTPConnectionPool and subclass HTTPSConnectionPool
  • PoolManager and subclass ProxyManager
  • socks.SOCKSProxyManager

(Since this could be tackled by a contributor who isn’t familiar with context managers, I preferred to err on the side of verbosity here.)

Let’s look at an example:

def test_redirect(self):
    http = PoolManager()
    self.addCleanup(http.clear)
    r = http.request("GET", "/redirect", ...)
    assert r.status == 303

This is equivalent to:

def test_redirect(self):
    http = PoolManager()
    try:
        r = http.request("GET", "/redirect", ...)
        assert r.status == 303
    finally:
        http.clear()

If PoolManager had a close() method that behavec like clear(), this would also work:

import contextlib

def test_redirect(self):
    with contextlib.closing(PoolManager()) as http:
        r = http.request("GET", "/redirect", ...)
        assert r.status == 303

Alternatively, if PoolManager implemented the context manager protocol (ie. had an __exit__ method), we could write:

def test_redirect(self):
    with PoolManager() as http:
        r = http.request("GET", "/redirect", ...)
        assert r.status == 303

This last variant is slightly better than the addCleanup variant, I think. But can we do better? I think pytest fixtures can help here. For example, using a pool_manager fixture:

import pytest

@pytest.fixture
def pool_manager():
    manager = PoolManager()
    try:
        yield manager
    finally:
        manager.clear()


def test_redirect(pool_manager):
    r = http.request("GET", "/redirect", ...)
    assert r.status == 303

This reduces verbosity in the tests themselves (look, only two lines left!). (I think that will also help with our async work because it will allow us to pass an AsyncPoolManager too, but that’s mostly hypothetical for now.)

Anyway, my proposal is to use the fixtures when there the classes are created without any parameters, and to use the with PoolManager(args, kwargs) as http: form otherwise.

What do you think of that plan, @sethmlarson?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
RatanShreshthacommented, May 29, 2019

I can open a PR for that.

0reactions
pquentincommented, Jun 19, 2019

You’re right, thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

unittest — Unit testing framework — Python 3.11.1 ...
The crux of each test is a call to assertEqual() to check for an expected result; assertTrue() or assertFalse() to verify a condition;...
Read more >
addCleanup vs tearDown - python - Stack Overflow
If you are using unittest to write your tests, definitely use addCleanup , it's much better than tearDown . Up until now, I've...
Read more >
How To Use unittest to Write a Test Case for a Function in ...
Tests written using the unittest module can help you find bugs in your programs, and prevent regressions from occurring as you change your ......
Read more >
A Beginner's Guide to Unit Tests in Python (2022) - Dataquest
Unit tests are for testing other small pieces of code, typically a single function or method, referred to as a unit. Here's how...
Read more >
Django Tutorial Part 10: Testing a Django web application
To write a test you derive from any of the Django (or unittest) test ... but if you test properly, you'll quickly end...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found