Python | Quickly test your Python code with Hypothesis

Introduction

No matter which programming language or framework you use, testing is very important. Hypothesis is an advanced testing library for Python. It allows parameterization when writing test cases, and then generates easy-to-understand test data that makes the test fail. You can find more bugs in the code with less work. The test library covers most situations and can indeed help you find errors in your code.

This article shows how to use Hypothesis to test in Python and provides some examples.

**How do we distinguish between tests? **

Before we start with attribute-based testing, we need to know the general differences in testing. There are different group testing methods, and the two most common methods are based on test method and test level. Let's start with the test level that most people have already heard of. In essence, there are four test levels (although people may also know or define other levels):

Different test levels focus on different things. Unit testing focuses on a specific part or function of the software. This can be a single function or part of a function. Instead, integration testing focuses on collaboration through the interfaces of software components. System testing goes even further and can test the entire system.

Now, we will look at the various test methods that exist.

The most common and known are static and dynamic tests. The so-called static testing is the process of not actually running the software under test, but statically checking the program code, interface, or document for possible errors. If the software or part of it is actually executed, we call it dynamic testing. Writing unit tests and integration tests are dynamic tests.

Another common method is the box method. Basically, it can be divided into white box testing and black box testing (and gray box testing as a mixture of the two). White box testing can verify the internal structure or working conditions of the program. Black box testing is the opposite. In black box testing, an application is treated as a black box and its interaction is tested. This means testing functions without knowing the internal implementation.

**What is attribute-based testing? **

Now that we quickly understand how to distinguish between tests, you may ask: What is attribute-based testing?

Property-based testing refers to writing logical statements (ie "attributes") that are true to your code, and then using automated tools to generate test inputs (generally, a certain Randomly generated input data of a specific type), and observe whether the attributes remain unchanged when the program accepts the input. If an input violates an attribute, the user proves that there is an error in the program and finds a convenient example that demonstrates the error.

Use Hypothesis for attribute-based testing

Let's take a simple example. Suppose you have two functions crement() and decrement(). An example implementation might look like this:

# increment_decrement.py

def increment(number: int)-> int:return number +1

def decrement(number: int)-> int:return number -1

You might write unit test code for both, as follows:

# test_increment_decrement_pytest.py

from increment_decrement import decrement
from increment_decrement import increment

def test_increment():
 x =5
 expected =6
 actual =increment(x)
 assert actual == expected

def test_decrement():
 x =5
 expected =4
 actual =decrement(x)
 assert actual == expected

Note: The test code is written using the pytest framework.

Of course, you can write more test scripts to test two functions with different values, and even parameterize the test. However, in the end you will test these two functions using predefined values.

It is different to write tests using attribute-based test libraries (such as Hypothesis). Here, you can specify the type to be tested and how the software works or behaves. Then the library generates a random value according to the specified type to perform the actual test function.

Let's see how to use Hypothesis to test our two functions.

# test_increment_decrement_hypothesis.py

from hypothesis import given
import hypothesis.strategies as st

from increment_decrement import decrement
from increment_decrement import increment

@ given(st.integers())
def test_increment(x):
 expected = x +1
 actual =increment(x)
 assert actual == expected

@ given(st.integers())
def test_decrement(x):
 expected = x -1
 actual =decrement(x)
 assert actual == expected

As you can see, both test scripts have a parameter x. The value of x is generated by Hypothesis using the integers() method. Hypothesis provides various methods. Essentially, these methods correspond to built-in types or other structures, and generate random data that matches a given type.

Sounds great, doesn't it? But what if we want to test a function with a specific value to make sure it can also use that value? Hypothesis provides a @example() decorator, in which you can define a value, even if the value does not belong to the randomly generated test data set, you can also pass the value to the corresponding function.

Let's take a simple example:

# div.py

def div(dividend: int, divisor: int)-> int:return dividend // divisor

We define a function div(), which accepts a divisor and a dividend and returns the quotient of the two. Please note that these two parameters are integer data, so the result should also be integer data. We use Python's // operator to perform integer division.

In order to test the div() function, we created a new test file test_div.py and wrote a test script called test_div().

# test_div.py

from hypothesis import example
from hypothesis import given
import hypothesis.strategies as st

from div import div

@ given(dividend=st.integers(), divisor=st.integers())
def test_div(dividend, divisor):if divisor ==0:
  expected =-1else:
  expected = dividend // divisor
 actual =div(dividend, divisor)
 assert actual == expected

Similarly, we use the integers() method of Hypothesis to generate the divisor and dividend values. The test script we write may or may not pass, depending on the value generated by Hypothesis during execution. To ensure that the value 0 is always passed to the div() function, we add @example(1, 0) to the test_div() function. Therefore, even if div() is not in the randomly generated data set, it will be called at least once with the value of the divisor 0.

If we run the test script as it is, test_div() will always fail. Therefore, let us modify the div() function to handle this situation and make the test pass:

# div.py

def div(dividend: int, divisor: int)-> int:if divisor ==0:return-1return dividend // divisor

summary

This article mainly talks about what attribute-based testing is and why it is useful. Also, you took a quick look at the Hypothesis library, which allows you to write attribute-based tests and execute them with pytest tests.

Love&Share [Finish]By the way, after reading it, I remember one-key four-connection, this is really important to me.

Recommended Posts

Python | Quickly test your Python code with Hypothesis
Gray-level co-occurrence matrix (with python code)
Speed up Python code with Cython
Create dynamic color QR code with Python
How to get started quickly with Python
python requests.get with header
Getting started with Python(18)
Getting started with Python(9)
Play WeChat with Python
Getting started with Python(4)
Web Scraping with Python
Getting started with Python (2)
Getting started with python-1
Python SMS bombing code
Getting started with Python(14)
Getting started with Python(7)
Getting started with Python(17)
Getting started with Python(15)
Getting started with Python(10)
Getting started with Python(11)
Getting started with Python(6)
Getting started with Python(3)
Getting started with Python(12)
Getting started with Python(5)
Getting started with Python (18+)
Getting started with Python(13)
Getting started with Python(16)