cari
Rumahpembangunan bahagian belakangC++MockManager dalam ujian unit - corak pembina yang digunakan untuk olok-olok

MockManager in unit tests - a builder pattern used for mocks

Beberapa tahun lalu saya menulis tentang perkara ini, tetapi kurang terperinci. Berikut ialah versi idea yang sama yang lebih halus.

Pengenalan

Ujian unit adalah kebaikan dan keburukan kepada pembangun. Mereka membenarkan ujian pantas kefungsian, contoh penggunaan yang boleh dibaca, percubaan pantas senario untuk komponen yang terlibat sahaja. Tetapi ia juga boleh menjadi kucar-kacir, memerlukan penyelenggaraan dan kemas kini dengan setiap perubahan kod dan, apabila dilakukan dengan malas, tidak boleh menyembunyikan pepijat daripada mendedahkannya.

Saya rasa sebab ujian unit begitu sukar adalah kerana ia dikaitkan dengan ujian, sesuatu selain daripada penulisan kod, dan juga ujian unit ditulis dengan cara yang bertentangan dengan kebanyakan kod lain yang kami tulis.

Dalam siaran ini, saya akan memberi anda corak mudah menulis ujian unit yang akan meningkatkan semua faedah, sambil menghapuskan kebanyakan disonans kognitif dengan kod biasa. Ujian unit akan kekal boleh dibaca dan fleksibel, sambil mengurangkan kod pendua dan tidak menambah kebergantungan tambahan.

Bagaimana untuk ujian unit

Tetapi pertama sekali, mari kita tentukan suite ujian unit yang baik.

Untuk menguji kelas dengan betul, ia perlu ditulis dengan cara tertentu. Dalam siaran ini, kami akan merangkumi kelas menggunakan suntikan pembina untuk kebergantungan, yang merupakan cara saya yang disyorkan untuk melakukan suntikan kebergantungan.

Kemudian, untuk mengujinya, kita perlu:

  • meliputi senario positif - apabila kelas melakukan perkara yang sepatutnya dilakukan, dengan pelbagai kombinasi tetapan dan parameter input untuk merangkumi keseluruhan fungsi
  • tutup senario negatif - apabila kelas gagal dengan cara yang betul apabila persediaan atau parameter input salah
  • ejek semua kebergantungan luar
  • simpan semua persediaan ujian, tindakan dan penegasan dalam ujian yang sama (yang biasanya dipanggil struktur Susun-Tindakan-Tegaskan)

Tetapi itu lebih mudah diucapkan daripada dilakukan, kerana ia juga membayangkan:

  • menyediakan kebergantungan yang sama untuk setiap ujian, dengan itu menyalin dan menampal banyak kod
  • menyediakan senario yang hampir sama, dengan hanya satu perubahan antara dua ujian, sekali lagi mengulangi banyak kod
  • mengeneralisasikan dan merangkum apa-apa, itulah yang biasanya dilakukan oleh pembangun dalam semua kod mereka
  • menulis banyak kes negatif untuk beberapa kes positif, yang rasanya seperti mempunyai lebih banyak kod ujian daripada kod berfungsi
  • perlu mengemas kini semua ujian ini untuk setiap perubahan pada kelas yang diuji

Siapa suka itu?

Penyelesaian

Penyelesaian adalah dengan menggunakan corak perisian pembina untuk mencipta ujian yang cair, fleksibel dan boleh dibaca dalam struktur Susun-Bertindak-Tegas, sambil merangkum kod persediaan dalam kelas yang melengkapkan suite ujian unit untuk perkhidmatan tertentu. Saya memanggil ini corak MockManager.

Mari kita mulakan dengan contoh mudah:

// the tested class
public class Calculator
{
    private readonly ITokenParser tokenParser;
    private readonly IMathOperationFactory operationFactory;
    private readonly ICache cache;
    private readonly ILogger logger;

    public Calculator(
        ITokenParser tokenParser,
        IMathOperationFactory operationFactory,
        ICache cache,
        ILogger logger)
    {
        this.tokenParser = tokenParser;
        this.operationFactory = operationFactory;
        this.cache = cache;
        this.logger = logger;
    }

    public int Calculate(string input)
    {
        var result = cache.Get(input);
        if (result.HasValue)
        {
            logger.LogInformation("from cache");
            return result.Value;
        }
        var tokens = tokenParser.Parse(input);
        IOperation operation = null;
        foreach(var token in tokens)
        {
            if (operation is null)
            {
                operation = operationFactory.GetOperation(token.OperationType);
                continue;
            }
            if (result is null)
            {
                result = token.Value;
                continue;
            }
            else
            {
                if (result is null)
                {
                    throw new InvalidOperationException("Could not calculate result");
                }
                result = operation.Execute(result.Value, token.Value);
                operation = null;
            }
        }
        cache.Set(input, result.Value);
        logger.LogInformation("from operation");
        return result.Value;
    }
}

Ini adalah kalkulator, seperti tradisi. Ia menerima rentetan dan mengembalikan nilai integer. Ia juga menyimpan hasil carian untuk input tertentu, dan log beberapa perkara. Operasi sebenar sedang diabstrak oleh IMathOperationFactory dan rentetan input diterjemahkan ke dalam token oleh ITokenParser. Jangan risau, ini bukan kelas sebenar, hanya contoh. Mari lihat ujian "tradisional":

[TestMethod]
public void Calculate_AdditionWorks()
{
    // Arrange
    var tokenParserMock = new Mock<itokenparser>();
    tokenParserMock
        .Setup(m => m.Parse(It.IsAny<string>()))
        .Returns(
            new List<calculatortoken> {
                CalculatorToken.Addition, CalculatorToken.From(1), CalculatorToken.From(1)
            }
        );

    var mathOperationFactoryMock = new Mock<imathoperationfactory>();

    var operationMock = new Mock<ioperation>();
    operationMock
        .Setup(m => m.Execute(1, 1))
        .Returns(2);

    mathOperationFactoryMock
        .Setup(m => m.GetOperation(OperationType.Add))
        .Returns(operationMock.Object);

    var cacheMock = new Mock<icache>();
    var loggerMock = new Mock<ilogger>();

    var service = new Calculator(
        tokenParserMock.Object,
        mathOperationFactoryMock.Object,
        cacheMock.Object,
        loggerMock.Object);

    // Act
    service.Calculate("");

    //Assert
    mathOperationFactoryMock
        .Verify(m => m.GetOperation(OperationType.Add), Times.Once);
    operationMock
        .Verify(m => m.Execute(1, 1), Times.Once);
}
</ilogger></icache></ioperation></imathoperationfactory></calculatortoken></string></itokenparser>

Jom bongkar sikit. Kami terpaksa mengisytiharkan olok-olok untuk setiap pergantungan pembina, walaupun kami sebenarnya tidak mengambil berat tentang pembalak atau cache, sebagai contoh. Kami juga terpaksa menyediakan kaedah olok-olok yang mengembalikan olok-olok lain, dalam kes kilang operasi.

Dalam ujian khusus ini, kebanyakannya kami menulis persediaan, satu baris Act dan dua baris Assert. Lebih-lebih lagi, jika kami ingin menguji cara cache berfungsi di dalam kelas, kami perlu menyalin tampal keseluruhannya dan hanya mengubah cara kami menyediakan mock cache.

Dan terdapat ujian negatif untuk dipertimbangkan. Saya telah melihat banyak ujian negatif melakukan sesuatu seperti: "sediakan hanya apa yang sepatutnya gagal. uji bahawa ia gagal", yang memperkenalkan banyak masalah, terutamanya kerana ia mungkin gagal untuk sebab yang berbeza dan kebanyakan masa ujian ini mengikuti pelaksanaan dalaman kelas dan bukannya keperluannya. Ujian negatif yang betul sebenarnya adalah ujian positif sepenuhnya dengan hanya satu keadaan yang salah. Tidak begitu di sini, untuk kesederhanaan.

Jadi, tanpa berlengah lagi, inilah ujian yang sama, tetapi dengan MockManager:

[TestMethod]
public void Calculate_AdditionWorks_MockManager()
{
    // Arrange
    var mockManager = new CalculatorMockManager()
        .WithParsedTokens(new List<calculatortoken> {
            CalculatorToken.Addition, CalculatorToken.From(1), CalculatorToken.From(1)
        })
        .WithOperation(OperationType.Add, 1, 1, 2);

    var service = mockManager.GetService();

    // Act
    service.Calculate("");

    //Assert
    mockManager
        .VerifyOperationExecute(OperationType.Add, 1, 1, Times.Once);
}

</calculatortoken>

Membongkar, tidak ada menyebut tentang cache atau logger, kerana kami tidak memerlukan sebarang persediaan di sana. Semuanya dibungkus dan boleh dibaca. Salin tampal ini dan menukar beberapa parameter atau beberapa baris tidak lagi hodoh. Terdapat tiga kaedah yang dilaksanakan dalam Arrange, satu dalam Act dan satu dalam Assert. Hanya butiran ejekan yang ringkas sahaja yang disarikan: rangka kerja Moq tidak disebutkan di sini. Malah, ujian ini akan kelihatan sama tanpa mengira rangka kerja mengejek yang diputuskan untuk digunakan.

Mari kita lihat kelas MockManager. Sekarang ini akan kelihatan rumit, tetapi ingat bahawa kami hanya menulis ini sekali dan menggunakannya berkali-kali. Keseluruhan kerumitan kelas ada untuk menjadikan ujian unit boleh dibaca oleh manusia, mudah difahami, dikemas kini dan diselenggara.

public class CalculatorMockManager
{
    private readonly Dictionary<operationtype>> operationMocks = new();

    public Mock<itokenparser> TokenParserMock { get; } = new();
    public Mock<imathoperationfactory> MathOperationFactoryMock { get; } = new();
    public Mock<icache> CacheMock { get; } = new();
    public Mock<ilogger> LoggerMock { get; } = new();

    public CalculatorMockManager WithParsedTokens(List<calculatortoken> tokens)
    {
        TokenParserMock
            .Setup(m => m.Parse(It.IsAny<string>()))
            .Returns(
                new List<calculatortoken> {
                    CalculatorToken.Addition, CalculatorToken.From(1), CalculatorToken.From(1)
                }
            );
        return this;
    }

    public CalculatorMockManager WithOperation(OperationType operationType, int v1, int v2, int result)
    {
        var operationMock = new Mock<ioperation>();
        operationMock
            .Setup(m => m.Execute(v1, v2))
            .Returns(result);

        MathOperationFactoryMock
            .Setup(m => m.GetOperation(operationType))
            .Returns(operationMock.Object);

        operationMocks[operationType] = operationMock;

        return this;
    }

    public Calculator GetService()
    {
        return new Calculator(
                TokenParserMock.Object,
                MathOperationFactoryMock.Object,
                CacheMock.Object,
                LoggerMock.Object
            );
    }

    public CalculatorMockManager VerifyOperationExecute(OperationType operationType, int v1, int v2, Func<times> times)
    {
        MathOperationFactoryMock
            .Verify(m => m.GetOperation(operationType), Times.AtLeastOnce);
        var operationMock = operationMocks[operationType];
        operationMock
            .Verify(m => m.Execute(v1, v2), times);
        return this;
    }
}
</times></ioperation></calculatortoken></string></calculatortoken></ilogger></icache></imathoperationfactory></itokenparser></operationtype>

Semua olok-olok yang diperlukan untuk kelas ujian diisytiharkan sebagai harta awam, membenarkan sebarang penyesuaian ujian unit. Terdapat kaedah GetService, yang akan sentiasa mengembalikan contoh kelas yang diuji, dengan semua kebergantungan diejek sepenuhnya. Kemudian terdapat kaedah With* yang secara atom menyediakan pelbagai senario dan sentiasa mengembalikan pengurus olok-olok, supaya mereka boleh dirantai. Anda juga boleh mempunyai kaedah khusus untuk penegasan, walaupun dalam kebanyakan kes anda akan membandingkan beberapa output dengan nilai yang dijangkakan, jadi ini di sini hanya untuk mengabsahkan kaedah Sahkan rangka kerja Moq.

Kesimpulan

Corak ini kini menjajarkan penulisan ujian dengan penulisan kod:

  • abstrak perkara yang anda tidak kisah dalam sebarang konteks
  • tulis sekali dan guna berkali-kali
  • Kod pendokumentasian diri yang boleh dibaca oleh manusia
  • kaedah kecil dengan kerumitan cyclomatic yang rendah
  • penulisan kod intuitif

Menulis ujian unit sekarang adalah remeh dan konsisten:

  1. segera pengurus olok-olok kelas yang anda ingin uji (atau tulis satu berdasarkan langkah di atas)
  2. karang senario khusus untuk ujian (dengan auto lengkap untuk langkah senario yang sedia ada)
  3. laksanakan kaedah yang anda ingin uji dengan parameter ujian
  4. semak semuanya adalah seperti yang diharapkan

Pengabstrakan tidak berhenti pada rangka kerja mengejek. Corak yang sama boleh digunakan dalam setiap bahasa pengaturcaraan! Binaan pengurus olok-olok akan sangat berbeza untuk TypeScript atau JavaScript atau sesuatu yang lain, tetapi ujian unit akan kelihatan dengan cara yang sama.

Semoga ini membantu!

Atas ialah kandungan terperinci MockManager dalam ujian unit - corak pembina yang digunakan untuk olok-olok. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Bagaimana Perpustakaan Templat St Standard (STL) berfungsi?Bagaimana Perpustakaan Templat St Standard (STL) berfungsi?Mar 12, 2025 pm 04:50 PM

Artikel ini menerangkan Perpustakaan Templat St Standard (STL), yang memberi tumpuan kepada komponen terasnya: bekas, iterator, algoritma, dan functors. Ia memperincikan bagaimana ini berinteraksi untuk membolehkan pengaturcaraan generik, meningkatkan kecekapan kod dan kebolehbacaan t

Bagaimanakah saya menggunakan algoritma dari STL (jenis, mencari, mengubah, dll) dengan cekap?Bagaimanakah saya menggunakan algoritma dari STL (jenis, mencari, mengubah, dll) dengan cekap?Mar 12, 2025 pm 04:52 PM

Artikel ini memperincikan penggunaan algoritma STL yang cekap dalam c. Ia menekankan pilihan struktur data (vektor vs senarai), analisis kerumitan algoritma (mis., Std :: Sort vs Std :: partial_sort), penggunaan iterator, dan pelaksanaan selari. Perangkap biasa seperti

Bagaimana saya mengendalikan pengecualian dengan berkesan di C?Bagaimana saya mengendalikan pengecualian dengan berkesan di C?Mar 12, 2025 pm 04:56 PM

Artikel ini butiran pengendalian pengecualian yang berkesan di C, meliputi percubaan, menangkap, dan membuang mekanik. Ia menekankan amalan terbaik seperti RAII, mengelakkan blok tangkapan yang tidak perlu, dan pengecualian pembalakan untuk kod yang mantap. Artikel ini juga menangani perf

Bagaimanakah saya menggunakan semantik bergerak di C untuk meningkatkan prestasi?Bagaimanakah saya menggunakan semantik bergerak di C untuk meningkatkan prestasi?Mar 18, 2025 pm 03:27 PM

Artikel ini membincangkan menggunakan semantik Move dalam C untuk meningkatkan prestasi dengan mengelakkan penyalinan yang tidak perlu. Ia meliputi pelaksanaan pembina bergerak dan pengendali tugasan, menggunakan STD :: bergerak, dan mengenal pasti senario utama dan perangkap untuk Appl yang berkesan

Bagaimanakah saya menggunakan julat dalam C 20 untuk manipulasi data yang lebih ekspresif?Bagaimanakah saya menggunakan julat dalam C 20 untuk manipulasi data yang lebih ekspresif?Mar 17, 2025 pm 12:58 PM

C 20 julat meningkatkan manipulasi data dengan ekspresi, komposiliti, dan kecekapan. Mereka memudahkan transformasi kompleks dan mengintegrasikan ke dalam kod sedia ada untuk prestasi dan kebolehkerjaan yang lebih baik.

Bagaimanakah saya menggunakan rujukan RValue dengan berkesan di C?Bagaimanakah saya menggunakan rujukan RValue dengan berkesan di C?Mar 18, 2025 pm 03:29 PM

Artikel membincangkan penggunaan rujukan RValue yang berkesan dalam C untuk bergerak semantik, pemajuan sempurna, dan pengurusan sumber, menonjolkan amalan terbaik dan penambahbaikan prestasi. (159 aksara)

Bagaimanakah penghantaran dinamik berfungsi di C dan bagaimana ia mempengaruhi prestasi?Bagaimanakah penghantaran dinamik berfungsi di C dan bagaimana ia mempengaruhi prestasi?Mar 17, 2025 pm 01:08 PM

Artikel ini membincangkan penghantaran dinamik dalam C, kos prestasinya, dan strategi pengoptimuman. Ia menyoroti senario di mana penghantaran dinamik memberi kesan kepada prestasi dan membandingkannya dengan penghantaran statik, menekankan perdagangan antara prestasi dan

Bagaimanakah pengurusan memori C berfungsi, termasuk petunjuk baru, memadam, dan pintar?Bagaimanakah pengurusan memori C berfungsi, termasuk petunjuk baru, memadam, dan pintar?Mar 17, 2025 pm 01:04 PM

Pengurusan memori C menggunakan petunjuk baru, memadam, dan pintar. Artikel ini membincangkan manual vs pengurusan automatik dan bagaimana penunjuk pintar menghalang kebocoran memori.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

VSCode Windows 64-bit Muat Turun

VSCode Windows 64-bit Muat Turun

Editor IDE percuma dan berkuasa yang dilancarkan oleh Microsoft

Versi Mac WebStorm

Versi Mac WebStorm

Alat pembangunan JavaScript yang berguna

DVWA

DVWA

Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini

SecLists

SecLists

SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.

Muat turun versi mac editor Atom

Muat turun versi mac editor Atom

Editor sumber terbuka yang paling popular