Isolating unit tests in python

As a 30-year software developer, mostly in OO languages, but a newbie at python, I’m looking to find what is best practise for isolating unit tests in python.

Let’s say I have the following, semi-pseudo-code. I know some_database_client isn’t a real database client:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>from some_database_client import connection
connection.connect('server_id', 'username', 'password')
def function_under_test():
return connection.get_value('some_value_reference') + 10
</code>
<code>from some_database_client import connection connection.connect('server_id', 'username', 'password') def function_under_test(): return connection.get_value('some_value_reference') + 10 </code>
from some_database_client import connection

connection.connect('server_id', 'username', 'password')

def function_under_test():
    return connection.get_value('some_value_reference') + 10

If I write a test for function_under_test(), then I’m effectively testing the potentially enormous amount of logic in connecting and retrieving the data from connection.

Instead, I really want to test that function_under_test() adds ten to the value retrieved.

This relates to a practical real-world example where the module-level variable connection (or it’s real-world equivalent) is referenced heavily all over the code.

Therefore, it would involve a large and therefore very risky change to pass connection as an argument to all the functions that use it. Without doing this though, I can’t easily separate the variable connection when I’m trying to unit-test the functions that use it. connection is instantiated before I even get to run the unit-test.

Is there a recommended way to isolate functions like this for testing? I can certainly think of many, many ways, but I suspect that some have more of the “Zen of Python” about them than others. e.g. Wrapping everything in classes is a possibility, but that is perhaps moving too far away from keeping stuff simple, which is a goal of python.

8

This relates to a practical real-world example where the module-level variable connection (or it’s real-world equivalent) is referenced heavily all over the code. Therefore, while it would involve a large and therefore very risky change to pass connection as an argument to all the functions that use it.

That’s the only clean solution. Too late now, but in the future avoid such hidden dependencies if possible. The only other option I can think of is to change the Python path to point to an alternate some_database_client with a stub connection when you run your unit tests.

However…

Instead, I really want to test that function_under_test() adds ten to the value retrieved.

You don’t really need to test this. You can prove the correctness of such a trivial function by inspection. Writing unit tests to show it adds ten regardless of whether the return value of connection is 0, positive, negative, odd or even is slower than just looking at it and it still doesn’t guarantee correctness. Knowing what not to test is just as important as knowing what to test.

2

First, initializing a global connection at the module level is really, really bad practice. Rather, if you have to do that, you should have something like

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>def connect():
connection.connect('server_id', 'username', 'password')
if __name__ == '__main__':
connect()
</code>
<code>def connect(): connection.connect('server_id', 'username', 'password') if __name__ == '__main__': connect() </code>
def connect():
   connection.connect('server_id', 'username', 'password')

if __name__ == '__main__':
   connect()

So that you only actually connect in main execution.

Fortunately, from your code example, even if you connect to the database at the start of the module, you can just ignore that assignment and assign a new mock connection in your test.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>def my_test():
connection = MockConnection()
function_under_test()
assert(...)
</code>
<code>def my_test(): connection = MockConnection() function_under_test() assert(...) </code>
def my_test():
   connection = MockConnection()
   function_under_test()
   assert(...)

FWIW I found Python really easy to test because if there’s some artifact, dependency, or function that was hard to work with, I’d just shove in an implementation that let me focus on the test.

3

It intrinsically has to do with a basic yet important OOP concept: Inversion of control.

One of the ways to reach it is Dependency Injection. In a few words, instead of calling a determined function specified in the body of the function, you’ll call a function given by the caller.

Introducing it to your problem:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>def function_under_test(connection):
return connection.get_value('some_value_reference') + 10
</code>
<code>def function_under_test(connection): return connection.get_value('some_value_reference') + 10 </code>
def function_under_test(connection):
    return connection.get_value('some_value_reference') + 10

Now, we need to pass an object that has the method get_value. In production, you’d pass the real connection object. When testing, however, you’d pass a mock (fake version) of it.

An example of how easy testing becomes:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class FakeConnection():
def get_value(self, reference):
return 30
def test_function():
connection = FakeConnection()
result = function_under_test(connection)
assert result == 40
</code>
<code>class FakeConnection(): def get_value(self, reference): return 30 def test_function(): connection = FakeConnection() result = function_under_test(connection) assert result == 40 </code>
class FakeConnection():
    def get_value(self, reference):
        return 30

def test_function():
   connection = FakeConnection()
   result = function_under_test(connection)

   assert result == 40

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật