pytest: testes reutilizáveis para diferentes implementações da mesma interface

Imagine que eu implementei um utilitário (talvez uma classe) chamadoBar em um módulofooe escreveu os seguintes testes para ele.

test_foo.py:

from foo import Bar as Implementation
from pytest import mark

@mark.parametrize(<args>, <test data set 1>)
def test_one(<args>):
    <do something with Implementation and args>

@mark.parametrize(<args>, <test data set 2>)
def test_two(<args>):
    <do something else with Implementation and args>

<more such tests>

Agora imagine que, no futuro, espero que diferentes implementações da mesma interface sejam escritas. Gostaria que essas implementações pudessem reutilizar os testes que foram escritos para o conjunto de testes acima: As únicas coisas que precisam mudar são

A importação doImplementation<test data set 1>, <test data set 2> etc.

Portanto, estou procurando uma maneira de escrever os testes acima de maneira reutilizável, que permita aos autores de novas implementações da interface poder usar os testes injetando a implementação e os dados de teste neles, sem precisar modificar o arquivo contendo a especificação original dos testes.

Qual seria uma maneira boa e idiomática de fazer isso no pytest?

==================================================== ==================

==================================================== ==================

Aqui está uma versão mais unittest que (não é bonita, mas) funciona.

define_tests.py:

# Single, reusable definition of tests for the interface. Authors of
# new implementations of the interface merely have to provide the test
# data, as class attributes of a class which inherits
# unittest.TestCase AND this class.
class TheTests():

    def test_foo(self):
        # Faking pytest.mark.parametrize by looping
        for args, in_, out in self.test_foo_data:
            self.assertEqual(self.Implementation(*args).foo(in_),
                             out)

    def test_bar(self):
        # Faking pytest.mark.parametrize by looping
        for args, in_, out in self.test_bar_data:
            self.assertEqual(self.Implementation(*args).bar(in_),
                             out)

v1.py:

# One implementation of the interface
class Implementation:

    def __init__(self, a,b):
        self.n = a+b

    def foo(self, n):
        return self.n + n

    def bar(self, n):
        return self.n - n

v1_test.py:

# Test for one implementation of the interface
from v1 import Implementation
from define_tests import TheTests
from unittest import TestCase

# Hook into testing framework by inheriting unittest.TestCase and reuse
# the tests which *each and every* implementation of the interface must
# pass, by inheritance from define_tests.TheTests
class FooTests(TestCase, TheTests):

    Implementation = Implementation

    test_foo_data = (((1,2), 3,  6),
                     ((4,5), 6, 15))

    test_bar_data = (((1,2), 3,  0),
                     ((4,5), 6,  3))

Qualquer pessoa (mesmo um cliente da biblioteca) escrevendo outra implementação dessa interface

pode reutilizar o conjunto de testes definido emdefine_tests.pyinjetar dados de teste próprios nos testessem modificar nenhum dos arquivos originais

questionAnswers(2)

yourAnswerToTheQuestion