dekorator mock.patch: tidak ada 1 argumen posisi yang diperlukan: 'mandiri'

Saya mencoba menambal variabel dalam modul settings selama metode pengujian dijalankan:

from unittest import mock

class Test(...):

    @mock.patch('settings.TARGET_SCORES_PER_SECTION', True)
    def test_register_user(self):

Saya mendapatkan kesalahan ini:

ERROR: tests.test_user.transplant_class.<locals>.C (test_register_user)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 1179, in patched
    return func(*args, **keywargs)
TypeError: test_register_user() missing 1 required positional argument: 'self'

Saya mencoba pendekatan yang berbeda, tidak dapat menemukan solusi.

Apa yang saya lakukan salah?

Versi ini berfungsi dengan baik:

    def test_register_user(self):
        with mock.patch('settings.TARGET_SCORES_PER_SECTION', True):
            self._test_register_user()

    def _test_register_user(self):

Dan saya berharap penggunaannya sebagai dekorator akan bekerja dengan cara yang sama.


person warvariuc    schedule 17.04.2019    source sumber
comment
Jangan lupa untuk mengimpor settings dan menambahkan tiruan yang dipatch ke parameter fungsi pengujian Anda seperti di def test_register_user(self, mock_target_scores):   -  person progmatico    schedule 19.04.2019
comment
Untuk apa yang saya uji, kedua pernyataan Anda salah.   -  person warvariuc    schedule 19.04.2019
comment
Salah adalah sedikit gambaran minimal. Kode apa yang sudah Anda uji? Periksa jawaban saya terlebih dahulu, semoga membantu.   -  person progmatico    schedule 19.04.2019
comment
Faktanya, ini salah hanya karena Anda perlu menambal seluruh pengaturan, bukan atributnya. Atau lihat di sini untuk alternatif jika Anda tidak ingin meniru seluruh modul pengaturan tetapi hanya atribut (menggunakan PropertyMock)   -  person progmatico    schedule 19.04.2019
comment
Saya perhatikan Anda tidak memiliki bagian as dalam pernyataan with, yang berarti Anda tidak ingin mengakses tiruan selain membuat tambalan dengannya. Ini juga bagus untuk kasus tiruan sederhana atau jika Anda menyiapkan objek lain untuk diteruskan ke patch dengan new   -  person progmatico    schedule 19.04.2019
comment
Saya sedang mengedit jawaban saya.   -  person progmatico    schedule 19.04.2019
comment
Meskipun jawaban saya berfungsi di kedua bentuk, saya tidak dapat mereproduksi pesan kesalahan persis Anda dengan mengubah parameter patch dan def dengan cara yang salah. Mungkinkah Anda lupa memasukkan self ke dalam metode kelas sejenak?   -  person progmatico    schedule 19.04.2019


Jawaban (1)


Jika saya memahami apa yang Anda coba lakukan, ini akan memberi Anda gambaran tentang cara melakukannya.

Saya telah membuat settings.py hanya menampung tugas False hingga TARGET_SCORES_PER_SECTION. Harus menyebutkan __main__ di patch hanya sedikit mengganggu, ia tidak akan menerima nama yang tidak memenuhi syarat.

import unittest
from unittest import TestCase
from unittest.mock import patch
import settings


def register_user():
    return settings.TARGET_SCORES_PER_SECTION


class Test(TestCase):

    @patch('__main__.settings')
    def test_register_user(self, mock_settings):
        # setup your mock
        mock_settings.TARGET_SCORES_PER_SECTION = True
        # test your function
        self.assertTrue(register_user())

if __name__ == '__main__':
    unittest.main()

Sunting:

Menurut saya untuk memahami pertanyaan OP dengan lebih baik, kode di atas juga dapat diubah menjadi ini jika Anda suka:

import unittest
from unittest import TestCase
from unittest.mock import patch
import settings


def register_user():
    return settings.TARGET_SCORES_PER_SECTION


class Test(TestCase):

    @patch('settings.TARGET_SCORES_PER_SECTION', True)
    def test_register_user(self):
        self.assertTrue(register_user())

    if __name__ == '__main__':
        unittest.main()

Dimana True adalah parameter new. Objek ini digunakan untuk menambal tempat yang Anda sebutkan di string tambalan. Ini mungkin lebih elegan tetapi mengharuskan Anda memiliki objek yang dikonfigurasi untuk diejek.

person progmatico    schedule 19.04.2019
comment
Solusi Anda berhasil, tetapi ini adalah solusinya. Pertanyaan saya tentang penggunaan mock.patch sebagai dekorator menurut dokumen dengan new argumen lolos. Meneruskan tiruan sebagai argumen fungsi dan mengaturnya dalam fungsi tidak terlihat bagus bagi saya. Lihat pembaruan pertanyaan saya. - person warvariuc; 19.04.2019
comment
@warvariuc, tapi itu bukan saya yang melakukannya (bukan pilihan). Itu adalah fitur dekorator. Dekorator mengubah tanda tangan fungsi pengujian Anda untuk menambahkan tiruan sebagai parameter. Anda bahkan dapat menumpuk dekorator dan mereka akan menambahkan semua tiruan pada tanda tangan. Bahkan jika Anda tidak menggunakannya di dalam, mereka harus ditulis dalam def. Itu sebabnya Anda mendapatkan kesalahan tentang self. - person progmatico; 19.04.2019
comment
Anda juga bisa mendekorasi kelas. Itu akan mengubah semua tanda tangan metode pengujian. - person progmatico; 19.04.2019
comment
Sebenarnya ITULAH sebuah pilihan, maaf. Dari dokumen, Jika patch() digunakan sebagai dekorator dan new dihilangkan, tiruan yang dibuat diteruskan sebagai argumen tambahan ke fungsi yang didekorasi. Jika patch() digunakan sebagai pengelola konteks, tiruan yang dibuat dikembalikan oleh pengelola konteks. - person progmatico; 19.04.2019
comment
Saya menemukan masalahnya. Ini pelari tes hidung2. Saat saya ingin menguji satu metode TestCase (./manage.sh runtests -r -v tests.test_user.Test.test_register_user), metode tersebut meneruskan fungsi yang tidak terikat ke self. Belum tahu mengapa hal itu terjadi dan bagaimana cara memperbaikinya, tetapi masalahnya sudah berbeda. mock.patch berfungsi dengan benar. Terima kasih atas waktu Anda. - person warvariuc; 19.04.2019