目次
導入
単体テストの実行方法
解決
結論は
ホームページ バックエンド開発 C++ モックマネージャーユニットテスト - モッキング用のビルダーモード

モックマネージャーユニットテスト - モッキング用のビルダーモード

Apr 04, 2025 am 08:06 AM
typescript

モックマネージャーユニットテスト - モッキング用のビルダーモード

私は数年前にこれについて書きましたが、それほど詳細ではありませんでした。これは同じアイデアのより洗練されたバージョンです。

導入

ユニットテストは、開発者にとっての祝福と呪いの両方です。機能、読みやすい使用例、迅速な実験に関与するコンポーネントのシナリオの迅速なテストを可能にします。しかし、それらは乱雑になる可能性があり、コードが変更されるたびにメンテナンスと更新が必要であり、怠け者に行われた場合、エラーを表示するのではなく非表示にすることはできません。

単位テストが非常に困難な理由は、コードライティングではなくテストに関連しているため、単体テストは他のほとんどのコードとは逆の方法で記述されているからです。

この投稿では、通常のコードでほとんどの認知的不協和を排除しながら、すべての利点を高めるユニットテストを作成するための簡単なパターンを提供します。単体テストは、重複コードを減らしながら、読みやすく柔軟なままであり、追加の依存関係は追加されません。

単体テストの実行方法

しかし、最初に、優れたユニットテストスイートを定義しましょう。

クラスを正しくテストするには、どういうわけか記述する必要があります。この投稿では、依存関係にコンストラクターインジェクションを使用するクラスを紹介します。これは、依存関係噴射を行うための私の推奨方法です。

次に、それをテストするためには、次のことが必要です。

  • ポジティブなシナリオをカバーする - クラスが行うべきことを実行するときに、設定と入力パラメーターのさまざまな組み合わせを使用して関数全体をカバーする
  • 否定的なシナリオをカバーする - 設定または入力パラメーターが間違っている場合、クラスは正しい方法で失敗します
  • すべての外部依存関係をシミュレートします
  • すべてのテスト設定、操作、およびアサーションを同じテストに保持します(一般的にアレンジアクトアサート構造と呼ばれます)

しかし、これは言うよりも簡単です。なぜなら、それも意味するからです。

  • テストごとに同じ依存関係を設定し、多くのコードをコピーして貼り付けます
  • 非常によく似たシナリオを設定し、テスト間で1回だけ変更を行い、再び多くのコードを繰り返します
  • 一般化され、カプセル化されているものはありません。これは、開発者が通常すべてのコードで行うことです
  • 非常に少数のポジティブな例で多くの否定的な例を書く
  • これらのテストはすべて、テストクラスへの変更ごとに更新する必要があります

誰がこれが好きですか?

解決

解決策は、ビルダーソフトウェアパターンを使用して、アレイアクトアサート構造でスムーズで柔軟で読みやすいテストを作成しながら、クラスのセットアップコードをカプセル化して特定のサービスのユニットテストスイートを補完することです。私はそれをmockmanagerモードと呼びます。

簡単な例から始めましょう:

 //テストされたクラス
パブリッククラスの計算機
{
    private readonly itkenparser tokenparser;
    private readonly imathopementFactory OperationFactory;
    Private Readonly Icacheキャッシュ。
    Private Readonly Ilogger Logger;

    パブリック計算(
        Itkenparser tokenparser、
        imatopperationFactory OperationFactory、
        Icacheキャッシュ、
        iloggerロガー)
    {
        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操作= null;
        foreach(トークンのvarトークン)
        {
            if(操作はnull)
            {
                Operation = OperationFactory.GetOperation(token.OperationType);
                続く;
            }
            if(結果はnull)
            {
                result = token.value;
                続く;
            }
            それ以外
            {
                if(結果はnull)
                {
                    新しいInvalidOperationException( "結果を計算できなかった");
                }
                result = operation.execute(result.value、token.value);
                操作= null;
            }
        }
        cache.set(input、result.value);
        logger.loginformation( "from Operation");
        return result.value;
    }
}
ログイン後にコピー

これは伝統としての計算機です。文字列を受け取り、整数値を返します。また、特定の入力の結果をキャッシュし、一部のコンテンツを記録します。実際の操作はImathopperationFactoryによって抽出され、入力文字列はItkenParserによってトークンに変換されます。心配しないでください、これは本当のコースではなく、単なる例です。 「従来の」テストを見てみましょう。

 [testmethod]
public void caluture_additionworks()
{
    // 整える
    var tokenparsermock = new mock <itkenparser>();
    Tokenparsermock
        .setup(m => m.parse(it.isany <string>())))
        .returns(
            新しいリスト<calculatortoken> {
                calculatortoken.addition、calculatortoken.from(1)、calculatortoken.from(1)
            }
        );

    var mathoperationfactorymock = new mock <imatopetionfactory>();

    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 Calculate(
        tokenparsermock.Object、
        MathOperationFactoryMock.Object、
        cachemock.Object、
        loggermock.object);

    // 活動
    service.calculate( "");

    //アサート
    MathOperationFactoryMock
        .verify(m => m.getoperation(OperationType.Add)、times.once);
    OperationMock
        .verify(m => m.execute(1、1)、times.once);
}
</ilogger></icache></ioperation></imatopetionfactory></calculatortoken></string></itkenparser>
ログイン後にコピー

少し開いてみましょう。たとえば、実際にロガーやキャッシュを気にしていなくても、各コンストラクターの依存関係の模擬を宣言する必要があります。工場を操作する場合は、別のシミュレーションを返すシミュレーション方法も設定する必要があります。

この特定のテストでは、主に設定、1つの行為、2行のアサートを書きました。また、クラスでキャッシュの仕組みをテストする場合は、コンテンツ全体をコピーして貼り付けてから、キャッシュモックのセットアップ方法を変更する必要があります。

考慮すべき否定的なテストもいくつかあります。多くのネガティブなテストが似たようなことをしているのを見てきました:「失敗するものを設定します。それをテストすることが失敗する」。これは、主にまったく異なる理由で失敗する可能性があるため、多くの問題をもたらします。ほとんどの場合、これらのテストは要件ではなくクラスの内部実装に従います。正しいネガティブテストは、実際には完全に肯定的なテストであり、1つの間違った状態しかありません。簡単にするために、これはここではそうではありません。

したがって、ポイントに戻ると、ここに同じテストがありますが、Mockmanagerを使用してください。

 [testmethod]
public void calculate_additionworks_mockmanager()
{
    // 整える
    var mockmanager = new calculatemockmanager()
        .withparsedtokens(new list <calculatortoken> {{
            calculatortoken.addition、calculatortoken.from(1)、calculatortoken.from(1)
        })
        .withoperation(OperationType.Add、1、1、2);

    var service = mockmanager.getService();

    // 活動
    service.calculate( "");

    //アサート
    モックマネージャー
        .verifyOperationExecute(OperationType.Add、1、1、times.once);
}

</calculatortoken>
ログイン後にコピー

開梱、キャッシュやロガーについては言及していません。セットアップを行う必要はありません。すべてがパッケージ化され、読みやすいです。これをコピーして貼り付けて、いくつかのパラメーターまたはいくつかの行を変更します。アレンジで実行される3つの方法があります。1つはACTに、もう1つはASSERTです。実質的なシミュレーションの詳細のみが抽象化されています。ここでのMOQフレームワークについては言及されていません。実際、このテストは、どのシミュレーションフレームワークを使用するかに関係なく同じように見えます。

Mockmanagerクラスを見てみましょう。今ではこれは複雑に思えますが、私たちはそれを一度だけ書いて、それをたくさん使うことを覚えておいてください。このクラスの全体的な複雑さは、人間が読みやすく、理解し、更新し、維持できるようにすることです。

パブリッククラスCalculatormockManager
{
    private readonly dictionary <operationtype>> operationmocks = new();

    パブリックモック<itokenparser> tokenparsermock {get; } = new();
    public mock <imathoperationfactory> mathoperationfactorymock {get; } = new();
    パブリックモック<icache> cachemock {get; } = new();
    public mock <ilogger> loggermock {get; } = new();

    public calculatormockmanager withparsedtokens(list <calculatortoken>トークン)
    {
        Tokenparsermock
            .setup(m => m.parse(it.isany <string>())))
            .returns(
                新しいリスト<calculatortoken> {
                    calculatortoken.addition、calculatortoken.from(1)、calculatortoken.from(1)
                }
            );
        これを返します。
    }

    パブリックcalculatormockmanager with operation(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;

        これを返します。
    }

    パブリック計算機GetService()
    {
        新しい計算機を返します(
                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);
        これを返します。
    }
}
</times></ioperation></calculatortoken></string></calculatortoken></ilogger></icache></imathoperationfactory></itokenparser></operationtype>
ログイン後にコピー

テストクラスに必要なすべてのモックは、パブリックプロパティとして宣言され、単体テストのカスタマイズを許可します。テスト対象のクラスのインスタンスを常に返すGetServiceメソッドがあり、すべての依存関係が完全に模倣されています。次に、withメソッドがあります。これは、さまざまなシナリオを自動的にセットアップし、常にリンクできるようにシミュレーションマネージャーに戻ります。特定のアサーションメソッドを使用することもできますが、ほとんどの場合、出力を期待値と比較するため、MOQフレームワークの検証方法を抽象化するためだけです。

結論は

このパターンは、テストライティングをコードライティングと並べるようになりました。

  • どんな文脈でも気にしない抽象的なもの
  • 一度書いて、複数回使用します
  • 人間の読み取り可能な自己記録コード
  • 低い円の複雑さの小さな方法
  • 直感的なコードライティング

現在、ユニットテストを書くことは簡単で一貫しています。

  1. テストするクラスの模擬マネージャーをインスタンス化します(または上記の手順に従って書く)
  2. テスト用の特定のシナリオを作成します(既存のカバーされたシナリオ手順を自動的に完了します)
  3. テストパラメーターを使用して、テストするメソッドを実行する
  4. すべてが期待に沿っていることを確認してください

抽象化は、シミュレーションフレームワークで停止しません。同じパターンを各プログラミング言語に適用できます! Mock Managerコンストラクトは、TypeScriptやJavaScriptなどでは非常に異なりますが、ユニットテストはほぼ同じように見えます。

これが役立つことを願っています!

以上がモックマネージャーユニットテスト - モッキング用のビルダーモードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

5 つの一般的な JavaScript メモリ エラー 5 つの一般的な JavaScript メモリ エラー Aug 25, 2022 am 10:27 AM

JavaScript はメモリ管理操作を提供しません。代わりに、メモリは、ガベージ コレクションと呼ばれるメモリ再利用プロセスを通じて JavaScript VM によって管理されます。

Vue3+TypeScript+Vite は画像などの静的リソースを動的に導入するためにどのように使用しますか? Vue3+TypeScript+Vite は画像などの静的リソースを動的に導入するためにどのように使用しますか? May 16, 2023 pm 08:40 PM

質問: Vue3+TypeScript+Vite プロジェクトに画像などの静的リソースを動的に導入するために require を使用する方法!説明: 現在プロジェクトを開発する場合(プロジェクトフレームワークはVue3+TypeScript+Vite)、静的リソースを動的に導入する、つまりimgタグのsrc属性値を動的に取得する必要があります。次のコード: Write コードをアップロードした後、波線エラーが報告され、エラー メッセージ: 名前 "require" が見つかりません。ノードのタイプ定義をインストールする必要がありますか? npmi --save-dev@types/node を試してください。 npmi--save-d 実行後の ts(2580)

MySQLを使用してTypeScriptにデータ型変換機能を実装する方法 MySQLを使用してTypeScriptにデータ型変換機能を実装する方法 Jul 29, 2023 pm 02:17 PM

MySQL を使用して TypeScript にデータ型変換関数を実装する方法 はじめに: データ型変換は、Web アプリケーションを開発するときに非常に一般的な要件です。データベースに格納されているデータを処理するとき、特に MySQL をバックエンド データベースとして使用するとき、多くの場合、クエリ結果のデータを必要な型に変換する必要があります。この記事では、MySQL を使用して TypeScript でデータ型変換を実装する方法を紹介し、コード例を示します。 1.準備:始める

Redis と TypeScript を使用してハイパフォーマンス コンピューティング関数を開発する方法 Redis と TypeScript を使用してハイパフォーマンス コンピューティング関数を開発する方法 Sep 20, 2023 am 11:21 AM

Redis と TypeScript を使用してハイ パフォーマンス コンピューティング機能を開発する方法の概要: Redis は、高いパフォーマンスとスケーラビリティを備えたオープン ソースのインメモリ データ構造ストレージ システムです。 TypeScript は、型システムとより優れた開発ツールのサポートを提供する JavaScript のスーパーセットです。 Redis と TypeScript を組み合わせることで、大規模なデータ セットを処理し、Redis のメモリ ストレージとコンピューティング機能を最大限に活用するための効率的なコンピューティング関数を開発できます。この記事ではその方法を説明します

Vue3 で TypeScript を使用する方法 Vue3 で TypeScript を使用する方法 May 13, 2023 pm 11:46 PM

フィールド名 enum で型を宣言するにはどうすればよいですか?設計上、type フィールドは列挙値である必要があり、呼び出し元によって任意に設定されるべきではありません。以下は、合計 6 つのフィールドを持つ Type の列挙宣言です。 enumType{primary="primary",success="success",warning="warning",warn="warn",//warningaliasdanger="danger",info="info",}TypeSc

Vue2 と比較した Vue3 の変更点: TypeScript の型推論の改善 Vue2 と比較した Vue3 の変更点: TypeScript の型推論の改善 Jul 07, 2023 pm 01:05 PM

Vue2 と比較した Vue3 の変更点: TypeScript の型推論の向上 Vue は、ユーザー インターフェイスを構築するための人気のある JavaScript フレームワークです。 Vue3 は Vue フレームワークの最新バージョンであり、Vue2 に基づいて多くの改善と最適化が行われています。その 1 つは、TypeScript の型推論の改善です。この記事では、Vue3 の型推論の改善点を紹介し、コード例を通して説明します。 Vue2 では、Vue コンポーネントを手動で設定する必要があります

Redis と TypeScript を使用してスケーラブルなフロントエンド アプリケーションを開発する Redis と TypeScript を使用してスケーラブルなフロントエンド アプリケーションを開発する Aug 01, 2023 pm 09:21 PM

タイトル: Redis と TypeScript を使用したスケーラブルなフロントエンド アプリケーションの開発 はじめに: 今日のインターネット時代では、スケーラビリティはあらゆるアプリケーションの重要な要素の 1 つです。フロントエンド アプリケーションも例外ではありません。ユーザーの増大するニーズを満たすには、効率的で信頼性の高いテクノロジーを使用して、スケーラブルなフロントエンド アプリケーションを構築する必要があります。この記事では、Redis と TypeScript を使用してスケーラブルなフロントエンド アプリケーションを開発する方法を紹介し、コード例を通じてそのアプリケーションを実証します。 Redis の概要

PHP の TypeScript を使用してより良いコードを作成する PHP の TypeScript を使用してより良いコードを作成する Jun 19, 2023 pm 06:31 PM

JavaScript の継続的な開発により、フロントエンド エンジニアは、型チェックやモジュール性の欠如など、大規模なプロジェクトで混乱やエラーを引き起こすことが多い JavaScript 自体のいくつかの問題に徐々に気づくようになりました。これらの問題を解決するために TypeScript が登場し、フロントエンド開発でますます人気のある言語になりました。バックエンド開発の分野では、PHP は常に非常に人気のあるスクリプト言語です。したがって、TypeScriptを組み合わせてPHPアプリケーションを開発します

See all articles