[PYTHON] Feel free to write a test with nose (in the case of + gevent)

There are various testing frameworks for python, but I personally like the framework called nose, so I would like to introduce it.

installation of nose

$ pip install nose

You may need sudo depending on your environment.

write a nose test case

Suppose you have the following function sum and function is_even in a module called hoge.

hoge.py


def sum(a, b):
	return a + b

def is_even(n):
	return (n % 2 == 0)

Create the following file test_hoge.py that inherits unittest.TestCase. Here, ʻeq_ to check if the value is the same as the expected ** value ** and ʻok_ to check if the value is ** true ** are imported from nose.tools and used. I will. As a common mechanism in the test framework, setUp and tearDown are provided for processing such as initialization / resource release before and after the test, so try inserting a print statement.

test_hoge.py


from unittest import TestCase
from nose.tools import ok_, eq_
from hoge import sum, is_even

class HogeTestCase(TestCase):
	def setUp(self):
		print 'before test'
	def tearDown(self):
		print 'after test'
	
	def test_sum(self):
		eq_(sum(1, 2), 3)
		eq_(sum(5, 11), 16)
		eq_(sum(0, 0), 0)

	def test_is_even(self):
		ok_(is_even(2))
		ok_(not is_even(3))

Run the test case

nose comes with a test runner command called nosetests. (It will be installed by pip install nose) If you execute nosetests here, it will be as follows.

$ nosetests
..
----------------------------------------------------------------------
Ran 2 tests in 0.003s

OK

When nosetests is executed, it will search for test-like files (including test in the file name) under the current directory, and will collect and execute classes that inherit from ʻunittest.TestCase. I didn't get the message that I should have printed with the print statement, because by default nose captures the output to standard output. You can see the output as is with the -s` option.

$ nosetests -s

Add the -v option to display the name of the test case you are executing by the method name as well as the dot.

$ nosetests -v

When I tried to execute it together, it became as follows.

$ nosetests -s -v
test_is_even (test_hoge.HogeTestCase) ... before test
after test
ok
test_sum (test_hoge.HogeTestCase) ... before test
after test
ok

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

You can also specify a file name for the nosetests command to run only tests on specific files. It would be convenient if development progressed and tests increased.

$ nosetests ./test_hoge.py

Other tools

Here are some other test tools for ʻok_ and ʻeq_. See nose's Testing tools page (http://nose.readthedocs.org/en/latest/testing_tools.html) for more information.

raises

Use raises as a decorator for tests that are likely to cause exceptions. Test the following function div where an exception is likely to occur.

fuga.py


def div(n, m):
	return n / m

The test case is below.

fuga_hoge.py


from unittest import TestCase
from nose.tools import eq_, raises
from fuga import div
class FugaTestCase(TestCase):
	def test_div(self):
		eq_(div(10, 5), 2)
		eq_(div(10, 10), 1)
		eq_(div(9, 3), 3)

	@raises(ZeroDivisionError)
	def test_div_zerodiv(self):
		div(10, 0)

	

Now you can check if the test case test_div_zerodiv is properly throwing the exception ZeroDivisionError.

timed

timed is a decorator that checks if a test case finishes within a specified amount of time (specified in seconds). Consider a test that checks that a function do_something, which takes about 0.1 seconds to process, finishes within 0.2 seconds, such as:

moge.py


import time
def do_something():
	time.sleep(0.1)

The test case looks like this:

test_moge.py


from unittest import TestCase
from nose.tools import timed
from moge import do_something

class MogeTestCase(TestCase):
    @timed(0.2)
    def test_do_something(self):
        do_something()

Write a test of your program using gevent

For programs that use gevent, it's a good idea to use the following decorators.

gtest decorator


import gevent
def gtest(func):
	def _gtest(*args, **kwargs):
		gevent.spawn(func, *args, **kwargs).join()
	_gtest.__name__ = func.__name__
	return _gtest

Let's test a program like the one below. _tick and _tacik move alternately, sending numbered strings such as tick1, tack1, tick2, tack2 to the queue alternately, and finally sucking out all the contents from the queue and returning it as an array. Will give you.

g.py


import gevent
import gevent.queue

def ticktack(n):
    q = gevent.queue.Queue()

    def _tick(_q, _n):
        for i in range(_n):
            _q.put('tick%d' % (i + 1))
            gevent.sleep()

    def _tack(_q, _n):
        for i in range(_n):
            _q.put('tack%d' % (i + 1))
            gevent.sleep()

    _tick_thread = gevent.spawn(_tick, q, n)
    _tack_thread = gevent.spawn(_tack, q, n)

    result = []
    while len(result) < n * 2:
        result.append(q.get())

    return result

Since gevent makes a decisive greenlet switch when gevent.sleep () is called, the spawned _tick first and the spawned _tack later are always called.

Let's test this with the decorator above.

test_g.py


from unittest import TestCase
from nose.tools import eq_
import gevent

from g import ticktack

import gevent
def gtest(func):
    def _gtest(*args, **kwargs):
        gevent.spawn(func, *args, **kwargs).join()
    _gtest.__name__ = func.__name__
    return _gtest

class GTestCase(TestCase):
    @gtest
    def test_ticktack(self):
        r1 = ticktack(1)
        eq_(r1, ['tick1', 'tack1'])
        r2 = ticktack(2)
        eq_(r2, ['tick1', 'tack1', 'tick2', 'tack2'])

Did you feel good?

Summary

--nose makes it easy and easy to write test cases --nosetests has various options and can be executed flexibly --If you devise a test case for a program that uses gevent, it's ok.

I hope it helps.

Recommended Posts

Feel free to write a test with nose (in the case of + gevent)
To write a test in Go, first design the interface
Write the test in a python docstring
Feel free to change the label of the legend in Seaborn in python
To output a value even in the middle of a cell with Jupyter Notebook
How to get a list of files in the same directory with python
I want to write in Python! (2) Let's write a test
How to identify the element with the smallest number of characters in a Python list?
Make a note of what you want to do in the future with Raspberry Pi
Recursively get the Excel list in a specific folder with python and write it to Excel.
I wrote a doctest in "I tried to simulate the probability of a bingo game with Python"
Write a table-driven test in C
Feel free to encrypt the disk
Process the contents of the file in order with a shell script
How to determine the existence of a selenium element in Python
How to check the memory size of a variable in Python
[Introduction to StyleGAN] I played with "The Life of a Man" ♬
Output the contents of ~ .xlsx in the folder to HTML with Python
I wrote the code to write the code of Brainf * ck in python
How to check the memory size of a dictionary in Python
How to get the vertex coordinates of a feature in ArcPy
How to create a large amount of test data in MySQL? ??
Write a script to calculate the distance with Elasticsearch 5 system painless
Create a function to get the contents of the database in Go
Yield in a class that inherits unittest.TestCase didn't work with nose (depending on the version of nose?)
How to write when you want to put a number after the group number to be replaced with a regular expression in re.sub of Python
The story of a Parking Sensor in 10 minutes with GrovePi + Starter Kit
Think about how to write a filter with the Shotgun API-Contact Versions
Generate a list packed with the number of days in the current month.
[Introduction to Python] How to sort the contents of a list efficiently with list sort
[Linux] Command to get a list of commands executed in the past
Test & Debug Tips: Create a file of the specified size in Python
I want to sort a list in the order of other lists
Setting to debug test by entering the contents of the library with pytest
Receive a list of the results of parallel processing in Python with starmap
[Introduction to Python] How to write a character string with the format function
Various comments to write in the program
Write the result of keyword search with ebaysdk to Google Spread Sheets
I made a program to check the size of a file in Python
I made a mistake in fetching the hierarchy with MultiIndex of pandas
I tried to display the altitude value of DTM in a graph
I tried to verify the result of A / B test by chi-square test
[Python & SQLite] I tried to analyze the expected value of a race with horses in the 1x win range ①
I wanted to know the number of lines in multiple files, so I tried to get it with a command
Various ways to read the last line of a csv file in Python
How to pass the execution result of a shell command in a list in Python
9 Steps to Become a Machine Learning Expert in the Shortest Time [Completely Free]
How to mention a user group in slack notification, how to check the id of the user group
Set the number of elements in a NumPy one-dimensional array to a power of 2 (0 padded)
[Python] Created a class to play sin waves in the background with pyaudio
How to count the number of elements in Django and output to a template
[AWS] Let's run a unit test of Lambda function in the local environment
I failed to install django with pip, so a reminder of the solution
Test the number of times you have thrown a query (sql) in django
I made an appdo command to execute a command in the context of the app
I want to set a life cycle in the task definition of ECS
A memorandum of how to execute the! Sudo magic command in Jupyter Notebook
SSH login to the target server from Windows with a click of a shortcut
I want to see a list of WebDAV files in the Requests module
Searching for an efficient way to write a Dockerfile in Python with poetry
I didn't have to write a decorator in the class Thank you contextmanager