2014-10-08 20 views
9

Hayal Etme foo modülünde Bar isimli bir yardımcı program (belki de bir sınıf) uyguladım ve bunun için aşağıdaki testleri yazdım.pytest: Aynı arabirimin farklı uygulamaları için yeniden kullanılabilir testler

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> 

Şimdi ileride aynı arayüzünün farklı uygulamaları yazılması beklenen, düşünün. O uygulamaları yukarıdaki test paketi için yazılmıştır testleri yeniden muktedir istiyorum: değiştirmeniz gerekir tek şey

  1. Implementation
  2. <test data set 1> ithalatı, <test data set 2> vb

Yukarıdaki testlerin tekrar kullanılabilir bir şekilde yazılması için bir yol arıyorum; bu, arayüze yeni uygulamaların yazarların uygulama ve test verilerini bunlara enjekte ederek testleri kullanabilmesini mümkün kılar. orijinal belirtimi içeren dosyayı değiştirmek zorunda testlerin

Bunu pytest'te yapmak için iyi, deyimsel bir yol ne olurdu?

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

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

İşte burada (güzel değil) çalışan bir sürümü.

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)) 

Herkes (kitaplığın hatta bir istemci) başka uygulama yazma bu arabirim

  • orijinal dosyalar

cevap

3

Bu parametrized test fixtures için büyük bir kullanım durumu herhangi değiştirmeden testler

  • içine
  • kendi test verilerini enjekte define_tests.py tanımlanan testlerin setini yeniden kullanabilirsiniz.

    Kodunuz şöyle görünebilir:

    from foo import Bar, Baz 
    
    @pytest.fixture(params=[Bar, Baz]) 
    def Implementation(request): 
        return request.param 
    
    def test_one(Implementation): 
        assert Implementation().frobnicate() 
    

    Bu iki kere test_one koşmak olurdu: Bir kez nerede Uygulama = Bar ve bir kez uygulanması = Baz.

    Uygulama yalnızca bir donanım olduğundan, kapsamını değiştirebileceğinizi veya daha fazla kurulum gerçekleştirebileceğinizi unutmayın (belki de sınıfı örneklendirin, belki de bir şekilde yapılandırabilirsiniz).pytest.mark.parametrize dekoratör ile kullanılırsa

    , pytest tüm permütasyon üretecektir. Örneğin, yukarıdaki kodu ve burada bu kodu varsayarak:

    • Uygulama = Bar, şey = 1
    • Uygulama = Bar:

      @pytest.mark.parametrize('thing', [1, 2]) 
      def test_two(Implementation, thing): 
          assert Implementation(thing).foo == thing 
      

      test_two aşağıdaki konfigürasyonlar ile, dört kez çalışır , şey = 2

    • Uygulama = Baz, şey = 1
    • Uygulama = Baz, şey = 2
  • +0

    Test tanımlarını içeren orijinal dosyalara dokunmadan? – jacg

    +0

    Donanım tanımını merkezi bir yere, daha yüksek bir düzeyde bir conftest.py dosyasına taşıyabilirsiniz. Belgeler burada: http://pytest.org/latest/fixture.html#sharing-a-fixture-across-tests-in-a-module-or-class-session dokunarak yeni yazarlar tutmak istiyor musunuz Belirli test dosyalarını veya test paketindeki herhangi bir şeyi? –

    +0

    * Herhangi bir * mevcut kodu değiştirmeden eklenti eklemek mümkün olmalıdır. Birkaç uyumlu uygulama ve testlerle bir kütüphane göndersem kütüphanenin müşterileri, kütüphaneyle gelen dosyaların * herhangi birini * değiştirmeden yeni uygulamaları * ve onların testlerini * ekleyebilmelidir. Bu, önemsiz olacaktı, yeni testler yaparak yeni sınavları tekrar kullanmak istediğim için değil. Fikstürü kütüphaneyle birlikte gelen bir conftest.py'ye taşımak, (bir şeyi kaçırmadıkça), genişleticinin kütüphaneyle birlikte gelen bir dosyayı değiştirmesini gerektirecektir. – jacg

    0

    sınıf mirası olmadan bunu yapamaz, ancak unittest.TestCase kullanmak zorunda değilsiniz. Daha fazla pytest yapmak için fikstürleri kullanabilirsiniz.

    Bu örnek fikstürü parametrizasyonunu için izin verir, ya da başka bir fixures kullanın.

    Ben basit bir örnek oluşturmak deneyin.

    class SomeTest: 
    
        @pytest.fixture 
        def implementation(self): 
         return "A" 
    
        def test_a(self, implementation): 
         assert "A" == implementation 
    
    
    class OtherTest(SomeTest): 
    
        @pytest.fixture(params=["B", "C"]) 
        def implementation(self, request): 
         return request.param 
    
    
    def test_a(self, implementation): 
        """ the "implementation" fixture is not accessible out of class """ 
        assert "A" == implementation 
    

    ve ikinci test başarısız

    def test_a(self, implementation): 
    >  assert "A" == implementation 
    E  assert 'A' == 'B' 
    E   - A 
    E   + B 
    
        def test_a(self, implementation): 
    >  assert "A" == implementation 
    E  assert 'A' == 'C' 
    E   - A 
    E   + C 
    
        def test_a(implementation): 
         fixture 'implementation' not found 
    

    içeri python_class = *Test tanımlamak zorunda unutma pytest.ini bu yeni uygulamaların yazarları testlerin yeni parametrelendirme eklemek sağlayacak Nasıl

    İlgili konular