Daftar dan hubungi dukungan untuk mendapatkan 100 pemeriksaan gratis.Daftar gratis
Ilustrasi alur kerja CarrierLookup untuk Menguji Integrasi Pencarian Operator Secara Offline dengan Fixture Respons
Gambaran visual alur kerja yang dibahas dalam artikel CarrierLookup ini.

Masukkan transport dan uji fixture respons sintetis yang eksplisit sebelum mengizinkan konsumen CarrierLookup menggunakan jaringan.

Uji mock API Carrier Lookup harus menggantikan transport HTTP, menolak akses jaringan yang tidak disengaja, dan menegaskan bagaimana aplikasi Anda menangani setiap hasil yang didokumentasikan. Fixture sintetis dapat menguji logika konsumen tanpa mengirimkan nomor telepon atau menghabiskan saldo.

Tempatkan titik uji sebelum permintaan HTTP

Pengimpor CRM dapat lolos uji jalur sukses (happy-path) namun tetap melabeli nomor yang tidak dapat ditentukan sebagai tidak valid. Pengimpor tersebut juga dapat lolos uji peramban yang dimodifikasi sementara backend-nya melakukan permintaan berbayar yang nyata. Tempatkan titik uji Anda pada fungsi backend yang melakukan pertukaran HTTP keluar.

Konsumen harus menerima dependensi transport alih-alih menemukan klien asli secara internal. Transport uji yang disuntikkan menerima jalur dan isi permintaan yang dituju, menegaskannya, dan mengembalikan amplop sintetis. Tidak ada kunci API dalam pengujian. Jauhkan kredensial aktif dari pekerjaan CI juga.

Gunakan pembatasan jaringan terpisah sebagai cadangan. Mock yang mengembalikan data yang nyaman bukanlah bukti bahwa setiap panggilan keluar telah dicegat. Tolak lalu lintas keluar di kontainer CI atau batas runner, dan gagalkan pekerjaan jika ada upaya akses jaringan. Penjaga tingkat bahasa membantu menangkap kesalahan umum tetapi tidak dapat mencakup subproses atau setiap pustaka jaringan.

Tentukan hasil sebelum menulis fixture

Layanan operator sinkron kami menggunakan service_type=carrier. Respons tunggal memiliki bidang data datar, termasuk identifier, carrier, underlying_carrier, number_type, country_code, region, dan city. Membaca data.extra.carrier berarti menguji bentuk yang tidak ada.

Fixture Penegasan Konsumen
Kode 0 dengan bidang alokasi Pertahankan nilai alokasi asli
Kode 0 dengan semua bidang alokasi kosong Pencarian selesai dengan nilai tidak tersedia
Kode 42200 Tidak dapat ditentukan; jangan buat keberhasilan kosong
Multi item dengan exists=false Tidak ada hasil normal; jangan tandai nomor terputus
Kode 42901 Cabang sibuk; tidak ada pembaruan CRM yang berhasil
Kode 50400 Cabang waktu habis; tidak ada pembaruan CRM yang berhasil

Nilai operator menjelaskan alokasi asli. Nilai tersebut tidak boleh mengisi bidang CRM yang disebut jaringan saat ini. Demikian pula, baik hasil alokasi kosong maupun exists=false tidak menetapkan validitas telepon. Gunakan label hasil aplikasi terpisah agar kueri pelaporan di kemudian hari tidak menggabungkan status ini secara tidak sengaja.

Jalankan rangkaian fixture sintetis kecil

Simpan kode berikut sebagai carrier_consumer_test.py dan jalankan python3 carrier_consumer_test.py. Kode ini menggunakan pustaka standar Python. Contoh ini adalah titik konsumen minimal, dengan pengidentifikasi sintetis dan nilai yang dipilih dengan sengaja; kode ini tidak pernah menghubungi CarrierLookup. Ganti client dan pengklasifikasi demonstrasi dengan adaptor Anda sendiri sambil tetap mempertahankan penegasan fixture.

import socket
import unittest
from unittest.mock import patch

FIELDS = ("carrier", "underlying_carrier", "number_type",
          "country_code", "region", "city")
A, B = "+12025550101", "+12025550102"  # Hanya data uji sintetis.

def classify(envelope):
    code = envelope["code"]
    if code != 0:
        return {42200: "undetermined", 42901: "busy",
                50400: "timeout"}.get(code, "error")
    data = envelope["data"]
    if data["service_type"] != "carrier":
        raise ValueError("unexpected service")
    return "completed" if data["carrier"] else "completed_empty"

def client(transport, identifiers):
    multi = len(identifiers) > 1
    path = "/api/v1/batch-check" if multi else "/api/v1/check"
    body = {"service_type": "carrier"}
    body["identifiers" if multi else "identifier"] = (
        identifiers if multi else identifiers[0])
    return transport(path, body)

def completed(identifier, carrier=""):
    return {"code": 0, "msg": "synthetic fixture", "data": {
        "service_type": "carrier", "identifier": identifier,
        **dict.fromkeys(FIELDS, ""), "carrier": carrier}}

class ConsumerTests(unittest.TestCase):
    def setUp(self):
        self.guard = patch.object(
            socket.socket, "connect",
            side_effect=AssertionError("network forbidden"))
        self.guard.start()
        self.addCleanup(self.guard.stop)

    def test_single_flat_data_and_outcomes(self):
        for value, expected in [("Example Allocation", "completed"),
                                ("", "completed_empty")]:
            def fake(path, body):
                self.assertEqual(path, "/api/v1/check")
                self.assertEqual(body, {"service_type": "carrier",
                                        "identifier": A})
                return completed(A, value)
            result = client(fake, [A])
            self.assertNotIn("extra", result["data"])
            self.assertNotIn("registered", result["data"])
            self.assertEqual(classify(result), expected)

    def test_error_branches(self):
        for code, expected in [(42200, "undetermined"),
                               (42901, "busy"), (50400, "timeout")]:
            with self.subTest(code=code):
                result = client(lambda path, body: {
                    "code": code, "msg": "synthetic error",
                    "data": None}, [A])
                self.assertEqual(classify(result), expected)

    def test_multi_order_and_no_result(self):
        def fake(path, body):
            self.assertEqual(path, "/api/v1/batch-check")
            self.assertEqual(body, {"service_type": "carrier",
                                    "identifiers": [B, A]})
            return {"code": 0, "msg": "synthetic fixture", "data": {
                "service_type": "carrier", "total": 2,
                "succeeded": 1, "failed": 1, "results": [
                    {"identifier": B, "exists": True,
                     **dict.fromkeys(FIELDS, "")},
                    {"identifier": A, "exists": False}]}}
        data = client(fake, [B, A])["data"]
        rows = data["results"]
        self.assertEqual(data["service_type"], "carrier")
        self.assertEqual([r["identifier"] for r in rows], [B, A])
        self.assertEqual(len(rows), data["total"])
        outcomes = ["completed" if r["exists"] else "no_result"
                    for r in rows]
        self.assertEqual(outcomes, ["completed", "no_result"])
        self.assertNotIn("carrier", rows[1])

    def test_guard_rejects_an_escape(self):
        with socket.socket() as sock:
            with self.assertRaisesRegex(AssertionError, "network forbidden"):
                sock.connect(("127.0.0.1", 9))

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

Contoh tersebut mengembalikan amplop yang sudah didekodekan dari transport-nya. Contoh ini menguji konstruksi permintaan dan penanganan hasil, bukan penguraian HTTP. Simpan fixture untuk status HTTP, header, dan JSON yang rusak di batas transport asli Anda juga. Secara khusus, respons 42901 menyertakan Retry-After; fixture header respons harus memverifikasi bahwa transport Anda mempertahankannya untuk pemanggil. Jangan melakukan hard-code interval percobaan ulang baru ke dalam pengklasifikasi hasil.

Penjaga soket sengaja menguji jalur kegagalannya sendiri. Penjaga ini memblokir metode koneksi soket proses Python ini; pembatasan keluar CI terpisah tetap diperlukan untuk jalur lain. Panggilan berbayar yang tidak disengaja harus menggagalkan pekerjaan, bukan menjadi fixture tambahan yang tidak disadari.

Buat penegasan multi-hasil peka terhadap kesalahan urutan

Fixture multi mengirimkan B sebelum A. Hal itu penting: pengujian yang mengirimkan pengidentifikasi yang diurutkan secara alfabetis dan menerima urutan yang sama dapat melewatkan adaptor yang mengurutkan respons. Cocokkan setiap pengidentifikasi yang dikembalikan dengan posisi inputnya dan tegaskan total panjangnya.

Item multi pertama menghasilkan hasil yang selesai dengan nilai alokasi kosong. Item kedua memiliki exists=false dan tidak ada bidang operator. Pertahankan perbedaan tersebut saat memetakan ke catatan aplikasi. Jika adaptor produksi Anda membuang baris yang gagal, fixture harus gagal karena baris berikutnya dapat bergeser ke kontak yang salah.

Tambahkan satu penegasan pada fungsi pemetaan CRM yang sebenarnya: pencarian yang tidak dapat ditentukan atau gagal harus membiarkan observasi alokasi sebelumnya tetap utuh atau menandainya secara eksplisit sebagai kedaluwarsa sesuai kebijakan Anda. Fungsi tersebut tidak boleh menimpa catatan dengan "nomor tidak valid." Pengujian yang sama harus menolak penurunan lokasi saat ini dari wilayah atau kota alokasi.

Waktu habis multi sinkron menggagalkan seluruh permintaan tanpa hasil parsial. Uji cabang waktu habis seluruh permintaan secara terpisah dari amplop sukses yang berisi item yang tidak berhasil. Itu adalah input yang berbeda bagi konsumen.

Jaga kepercayaan offline terpisah dari verifikasi langsung

Pengujian ini menetapkan bagaimana kode Anda merespons kontrak yang diwakili oleh fixture. Pengujian ini tidak menunjukkan ketersediaan penyedia saat ini, penerimaan negara, izin akun, atau penagihan. Fixture buatan juga tidak dapat membuktikan bahwa penyedia langsung akan mengembalikan bidang alokasi tertentu untuk nomor tertentu.

Simpan asal fixture di samping pengujian: CarrierLookup API reference, tanggal peninjauan, dan bidang yang dikonsumsi adaptor Anda. Perbarui fixture saat kontrak yang didokumentasikan berubah, lalu periksa apakah data aplikasi lama memerlukan jalur baca yang kompatibel.

Jalankan uji coba langsung yang diotorisasi secara terpisah jika verifikasi integrasi memerlukannya, menggunakan input yang disetujui dan anggaran saldonya sendiri. Jangan membuat CI biasa bergantung pada panggilan tersebut. Mulailah dengan mengganti satu impor klien langsung di rangkaian pengujian Anda dengan transport yang disuntikkan dan konfirmasikan bahwa upaya pelarian jaringan langsung gagal.

Pelajari Lebih Lanjut

Pilih informasi produk yang sesuai dengan langkah berikutnya dalam alur kerja Anda.

Sumber