Unit testing and test-driven development in Python

What are the different types of software testing?

Generally, we can say that there are four types of software testing:

  • Unit testing: Focus on specific units or components of the software to determine whether each unit is fully functional.

  • Integration testing: Includes combined testing of individual building blocks or components. It checks whether there are any interface defects between the various functions.

  • System testing: System testing is a test conducted on a complete integrated system to evaluate whether the system meets its specific requirements.

  • Acceptance test: This test is performed before the software is released in the production environment. Users will test the system to determine whether the application meets their business needs

Unit test specification:

  • Test a single function

  • Tests should be written for each functional test case type (all positive and negative test cases)

  • It should be executed in the development environment

  • Loading and execution time should not take more time, because developers need them to execute from time to time, so it should be fast enough

  • Testing should be performed automatically

What is Test Driven Development or TDD?

In this process, the test unit is the actual code before written.

Now, you must be wondering how to write test cases before writing actual functions. It is not that we have to write all the test cases and then write the complete code, but start to write test cases for one of the functions, and then write the code to pass the test. In this way, our code and tests will continue to grow. The following steps are very important in the TDD method:

1) First write a failed unit test.

2) Then write enough code to make the test pass

3) Refactor unit test and production code to make it clean

4) Repeat the process until the function is completed

In order to understand it clearly, I will take you through an example.

We will use a simple example to understand the purpose. Our function checks whether the input value is even or odd. Since I will use the "pytest" framework, we need to install it first. I personally prefer to use "pytest" rather than "unittest" framework because it is easy to use and learn, and both frameworks have their own advantages, so please choose according to your use case.

python -m pip install pytest
 
Therefore, the following are test cases for our function:
  • Can I call evenOdd()
  • If I pass an even number, it should return "even number"
  • If I pass an odd number, it should return "odd number"
  • If I pass anything other than an integer, then an exception should be thrown

Let's check each test case at once, so we are now testing whether the "evenOdd()" function can be called. According to the steps previously written, we need to write a failed unit test first. Below, I call it before defining the function.

 
#test_evenodd.py
import pytest

def test_call_evenOdd():
    evenOdd(1)

 

We can run the above test by using the command "pytest" as shown below:

In the "pytest_unittest" folder, I have many other test files, and when all the tests pass, it will show a dot ".". If the test fails, "F" will be written on the console as shown in the screenshot above. As expected, the test fails because we don't have the function evenOdd(). Now, we will enter the second step, which is "write enough code to make the test pass"

 
#test_evenodd.py
import pytest

def evenOdd(value):
    return

def test_call_evenOdd():
    evenOdd(1)

 

The result of the above test is:

Many people learn python and don't know where to start.
Many people learn python and after mastering the basic grammar, they don't know where to find cases to get started.
Many people who have done case studies do not know how to learn more advanced knowledge.
So for these three types of people, I will provide you with a good learning platform, free to receive video tutorials, e-books, and the source code of the course!
QQ group: 721195303

 

From the output, we can see that the test has passed. Now, we will enter the third step, which is "refactoring unit tests and production code to make it tidy." So what needs to be refactored? Actually not. Now let's move to the second test case. "If I pass an even number, it should return "even"" and the failed test case will look like this:

 
#test_evenodd.py
import pytest

def evenOdd(value):
    return 

def test_call_evenOdd():
    evenOdd(1)

def test_check_even():
    retval = evenOdd(2) 
    assert retval=='even'

 

Now, I will write enough code to pass the test:

 
#test_evenodd.py
import pytest

def evenOdd(value):
    return 'even'

def test_call_evenOdd():
    evenOdd(1)

def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

 

Now we can see that the test has passed.

Now let's check if there is anything that needs to be refactored? Yes, we can refactor the test because we copied the function call in the two test cases. Therefore, the refactored code will be:

 
#test_evenodd.py
import pytest

def evenOdd(value):
    return 'even'

def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

 

Now for the next test case: if I pass an odd number, it should return "odd number"

The failed test case is as follows:

 
#test_evenodd.py
import pytest

def evenOdd(value):
    return 'even'

def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

def test_check_odd():
    retval = evenOdd(1)
    assert retval== 'odd'

 

Now we need to write code to make the test pass.

 
#test_evenodd.py
import pytest

def evenOdd(value):
    if value%2==0:
        return 'even'
    else:
        return 'odd'

def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

def test_check_odd():
    retval = evenOdd(1)
    assert retval== 'odd'
 

Here, I don't see anything that can be refactored. Now let's move to the last test case: if I pass an integer other than an integer, an exception should be raised.

The failed test case is as follows:

 
#test_evenodd.py
import pytest

def evenOdd(value):
    if value%2==0:
        return 'even'
    else:
        return 'odd'

def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

def test_check_odd():
    retval = evenOdd(1)
    assert retval== 'odd'

def test_check_int():
    with pytest.raises(TypeError):
        evenOdd(1.5)
 

Now, I will raise TypeError in the function as follows:

#test_evenodd.py
import pytest

def evenOdd(value):
    if type(value)==int:
        if value%2==0:
            return 'even'
        else:
            return 'odd'
    else:
        raise TypeError


def test_check_even():
    retval = evenOdd(2)
    assert retval=='even'

def test_check_odd():
    retval = evenOdd(1)
    assert retval== 'odd'

def test_check_int():
    with pytest.raises(TypeError):
        evenOdd(1.5)

 

And all our tests passed:

In this way, we have achieved the final function. The main purpose of writing this article is to take you through the entire journey of the TDD method. Now the question is, why should we follow the TDD method? The benefits of TDD are listed below.

Benefits of the TDD method:

  • Provide you with instant feedback on what is being developed.

  • With instant feedback, you can confidently change features or enhance current code

  • This contributes to the maintainability and scalability of the project or code

  • Most importantly, it records the code, which helps developers understand how the actual code behaves


I still want to recommend the Python learning group I built by myself : 721195303. All students in the group are learning Python. If you want to learn or are learning Python, you are welcome to join. Everyone is a software development party and shares dry goods from time to time (only Python software development related), including a copy of the latest Python advanced materials and zero-based teaching compiled by myself in 2021. Welcome friends who are in advanced and interested in Python to join!

Guess you like

Origin blog.csdn.net/aaahtml/article/details/114277809