universe-proton / universe-topology

A universal computer knowledge topology for all the programmers worldwide.
Apache License 2.0
50 stars 0 forks source link

How to elegantly specify fixture usage at the test module level in pytest? #4

Open justdoit0823 opened 7 years ago

justdoit0823 commented 7 years ago

With pytest test framework, we may define a module scope server fixture in conftest.py as the following:


import pytest
from pytest_localserver.http import WSGIServer

def app(environ, start_response):
    """A simple WSGI application"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return [environ['PATH_INFO'].encode()]

@pytest.fixture(scope='module')
def testserver():
    """Define the test WSGI server."""
    server = WSGIServer(host='127.0.0.1', port=8031, application=app)
    server.start()
    yield server
    server.stop()

and writing cases to test the server behaviour in another Python module.

Here are some different ways to write such test cases.


import requests

url = 'http://127.0.0.1:8031'

class TestFooGroup:

    def test_foo_a(self, testserver):
        res = requests.get(url + '/foo/a')
        assert res.content.decode() == '/foo/a'

    def test_foo_b(self, testserver):
        res = requests.get(url + '/foo/b')
        assert res.content.decode() == '/foo/b'

class TestBarGroup:

    def test_bar_a(self, testserver):
        res = requests.get(url + '/bar/a')
        assert res.content.decode() == '/bar/a'

    def test_bar_b(self, testserver):
        res = requests.get(url + '/bar/b')
        assert res.content.decode() == '/bar/b'

Run command pytest test_request_a.py to start test.


import requests

url = 'http://127.0.0.1:8031'

class TestFooGroup:

    def test_foo_a(self):
        res = requests.get(url + '/foo/a')
        assert res.content.decode() == '/foo/a'

    def test_foo_b(self):
        res = requests.get(url + '/foo/b')
        assert res.content.decode() == '/foo/b'

class TestBarGroup:

    def test_bar_a(self):
        res = requests.get(url + '/bar/a')
        assert res.content.decode() == '/bar/a'

    def test_bar_b(self):
        res = requests.get(url + '/bar/b')
        assert res.content.decode() == '/bar/b'

Except the above code, we nedd a pytest configuration file pytest.ini to run the test.


[pytest]

usefixtures = testserver

We can include all fixtures require by project here.


import requests

url = 'http://127.0.0.1:8031'

def test_server(testserver):
    pass

class TestFooGroup:

    def test_foo_a(self):
        res = requests.get(url + '/foo/a')
        assert res.content.decode() == '/foo/a'

    def test_foo_b(self):
        res = requests.get(url + '/foo/b')
        assert res.content.decode() == '/foo/b'

class TestBarGroup:

    def test_bar_a(self):
        res = requests.get(url + '/bar/a')
        assert res.content.decode() == '/bar/a'

    def test_bar_b(self):
        res = requests.get(url + '/bar/b')
        assert res.content.decode() == '/bar/b'

In this way, we can write a module level test function to touch the testserver fixture.


import pytest
import requests

url = 'http://127.0.0.1:8031'
pytestmark = pytest.mark.usefixtures('testserver')

class TestFooGroup:

    def test_foo_a(self):
        res = requests.get(url + '/foo/a')
        assert res.content.decode() == '/foo/a'

    def test_foo_b(self):
        res = requests.get(url + '/foo/b')
        assert res.content.decode() == '/foo/b'

class TestBarGroup:

    def test_bar_a(self):
        res = requests.get(url + '/bar/a')
        assert res.content.decode() == '/bar/a'

    def test_bar_b(self):
        res = requests.get(url + '/bar/b')
        assert res.content.decode() == '/bar/b'

With usefixtures function, we can specify a module level fixture.

You can get the detail at pytest document using-fixtures-from-classes-modules-or-projects

In my opinion, when we don't refer fixture variable in test method, version d is the most elegant, version c is next.

What's your opinion?