Bagaimana cara menangani parameter global dengan benar untuk pengujian unit dengan python?

11

Kami menerapkan banyak algoritma yang biasanya memiliki banyak parameter yang dibagikan, diketahui publik, dan relevan dengan keamanan.

Saat ini, kami cukup menggunakan kelas yang menampung semua parameter dan dua objek global yang telah ditentukan:

class PublicParams(object):
    p = q = 0

    def __init__(self, p, q):
        self.p = p
        self.q = q

# used for tests
publicParams_test = PublicParams(15,7)               

# Some 2048 bit numbers for example
publicParams_secure = PublicParams(128378947298374928374,128378947298374928374)  

Algoritme kemudian mengambil PublicParamsobjek sebagai argumen yang default ke produktifpublicParams_secure

def AlgoOne(n, publicParams = publicParams_secure):
    # do stuff with publicParams.p
    # ...
    AlgoTwo(x, publicParams)

dan

def AlgoTwo(x, publicParams= publicParams_secure):
    # do stuff with publicParams.q

Dengan cara ini kami masih dapat menyuntikkan parameter publik yang berbeda untuk pengujian unit yang lebih mudah:

class AlgoOneTest(unittest.TestCase):
    def test(self):
        # compare with manually computed result
        self.assertTrue(AlgoOne(1, publicParams_test) == 10) 

Apa yang saya tidak suka tentang pendekatan ini:

  • Memberikan nilai publicParamsdefault menjadikannya opsional ketika memanggil beberapa algoritma. Namun, menjadi mudah untuk melupakannya ketika memanggil AlgoTwodari dalam AlgoOne, yang akan menghasilkan dua objek yang berbeda digunakan jika objek uji dilewatkan keAlgoOne

Apakah ada cara yang lebih baik yang kurang rentan tetapi masih menawarkan fleksibilitas untuk pengujian unit? Apakah ini benar-benar praktik terbaik?

netik
sumber

Jawaban:

1

Buat file konfigurasi test_config.pydan production_config.py. Pilih salah satu dari mereka menggunakan variabel lingkungan atau argumen baris perintah. Impor (atau baca / parse, jika Anda memilih .json/ .txtbukan .py), dan buat hasilnya tersedia untuk seluruh program melalui objek global dalam modul yang dapat Anda impor di mana saja.

Ini sangat mirip dengan apa yang sudah Anda lakukan, kecuali bahwa ia mengambil satu langkah lebih jauh, dari cakupan global ke shell dari mana Anda memanggil python. Keuntungannya adalah bahwa tidak ada lagi risiko secara tidak sengaja menggabungkan produksi dan konfigurasi pengujian: Anda tidak dapat membaca kedua file dalam sesi python yang sama, karena hanya ada satu variabel lingkungan / baris perintah.

maks
sumber
0

Ada beberapa hal yang dapat Anda lakukan.

  • Berhenti menggunakan global
  • Berhenti menggunakan default
  • Selalu uji melalui metode pembantu pribadi yang tidak memungkinkan penggunaan default

    def _AlgoOne(n, publicParams):
        return AlgoOne(n, publicParams)
    

Tentu saja salah satu dari opsi itu banyak pekerjaan, tetapi Anda tidak akan bertanya apakah ini bukan masalah bagi Anda.

candied_orange
sumber
0

Kita selalu bisa memisahkan pengumpulan nilai dari konteks global dan pemrosesan parameter-parameter itu.

def do_the_thing():
    """Provides the public (rather untestable) context.
    _do_the_thing(global1, global2, publicParams)"""

def _do_the_thing(blah, blah, blah):
    "Actually does the thing"
    pass
pengguna166988
sumber