0

まあ、私はテストにまったく慣れていませんが、プログラミングを次のレベルに引き上げて、テストを開始したいと思います。単体テストではなく、高レベルのテストです。たとえば、次のようにします。ジョブを挿入し、結果で入力を確認して有効かどうかを確認します。または別の例: ジョブを挿入し、ワーカー X がそれを開始しました。ここで、ジョブとワーカーの両方のプロパティをチェックして、それらが有効な状態にあるかどうかを確認します。

しかし、これは非常に複雑なので、各テストで環境とインスタンスを実行することを考えていました。各環境はサーバーのインスタンスを作成し、空のデータベースを割り当てて作業します。

たとえば、開始ジョブの高レベルのケース:

var environment = new GenericEnvironment(test); // test will be used to throw errors within the environment when something goes wrong.
environment.insertWorker({name: 'bla bla', number 99});
environment.insertARandomProduct();
environment.insertJob({productId: product._id})
environment.startJob({workerId: worker._id})
var environmentValidator = new environmentValidators.StartJobEV()
var job = environment.getLastInsertedJob(environment, test);
environment.validate(job);
// node.js (Javascript on server)

この例は、実際には非同期コールバックを使用するため、非常に単純化されています。

environmentValidator は、環境からのデータを使用して、ジョブが有効な状態にあるかどうかを確認します。また、たとえば、ジョブで作業しているワーカーを取得して、状態がビジーかどうかを確認します。

しかし、私はこれが非常に優れているとは思いません。私はテストの作成を始めたばかりなので、これらの高レベルのテストを行う方法を改善できるかどうか尋ねます.

また、そのようなテストのための既存のフレームワークがあるかどうかを知りたいですか?

ありがとう

実際のコードですが、ジョブを挿入した後の状態を確認するためだけです:

    var serverManager = new ServerManager(test.getPathForDatabase());
    require('production/tests/tottys/_environments/DefaultEnvironment');
    var environment = new production.tests.tottys._environments.DefaultEnvironment(test, serverManager);

    var dummyData = {}

    test.addStep('initEnvironment', function(nextStep){
        environment.init();
        environment.addListener('afterInitialized', function(){
            nextStep();
        }, this);
    });

    test.addStep('insertWorker', function(nextStep){
        dummyData.worker = environment.insertRandomWorker(function(data){
            nextStep();
        });
    });

    test.addStep('insertProduct', function(nextStep){
        dummyData.product = environment.insertRandomProduct(function(data){
            nextStep();
        });
    });

    test.addStep('insertJob', function(nextStep){
        var worker = environment.getLastInsertedWorker();
        var product = environment.getLastInsertedProduct();
        dummyData.job = environment.insertRandomJob(worker, product, function(data){
            nextStep();
        });
    });

    test.addStep('updateWorker', function(nextStep){
        environment.updateWorker({workerId: environment.getLastInsertedWorker()._id}, function(data){
            nextStep();
        });
    });

    test.addStep('validateInsertedJob', function(nextStep, test){
        require('production/tests/tottys/_environmentValidators/AfterJobInserted');
        var EV = new production.tests.tottys._environmentValidators.AfterJobInserted(environment, test);
        var job = environment.getLastInsertedJob();
        EV.addListener('validationEnded', function(e){
            nextStep();
        });
        EV.validate(job, dummyData);
    });
    test.start();

そして検証ファイル:

qx.Class.define("production.tests.tottys._environmentValidators.AfterJobInserted", {
     extend: qx.core.Object


    ,properties: {
    }


    ,events: {
        validationEnded: 'qx.event.type.Data'
    }


    ,construct: function(environment, test){
        this.__environment = environment;
        this.__test = test;
    }


    ,members: {
        validate: function(job, dummyData){
            this.__job = job;
            this.__dummyData = dummyData;
            this.__environment.getWorkerForJob(job, this.__afterWorkerReturned, this);
            this.__environment.getProductForJob(job, this.__afterProductReturned, this);
        }



        ,__afterWorkerReturned: function(worker){
            this.__worker = worker;
            this.__tryStartValidation();
        }



        ,__afterProductReturned: function(product){
            this.__product = product;
            this.__tryStartValidation();
        }



        ,__tryStartValidation: function(){
            if(this.__preConditionsAreValid()){
                this.__startValidation();
            }
        }



        ,__preConditionsAreValid: function(){
            if(this.__worker && this.__product){
               return true;
            }
            return false;
        }



        ,__startValidation: function(){
            var test = this.__test;
            var dummyData = this.__dummyData;
            var job = this.__job;
            var worker = this.__worker;
            var product = this.__product;

            test.add("Expect job not to be done.", function(expect){
                expect(job.done).toBe(false);
            })

            test.add("Expect job's requested quantity to be the same as requested.", function(expect){
                expect(job.qtdRequested).toBe(dummyData.job.qtdRequested);
            })

            test.add("Expect job's missing quantity be the same as requested.", function(expect){
                expect(job.qtdMissing).toBe(dummyData.job.qtdRequested);
            })

            test.add("Expect to be requested by the same request type.", function(expect){
                expect(job.requestedByType).toBe('manager')
            })

            test.add("Expect job not to be done.", function(expect){
                expect(job.done).toBe(false);
            })

            test.add("Expect job's done quantity to be '0' (Number)", function(expect){
                expect(job.qtdDone).toBe(0);
            })

            test.add("Expect job to not have any time frames.", function(expect){
                expect(job.timeFrames && job.timeFrames.length > 0).notToBe(true);
            })

            test.add("Expect job's date end to not exist.", function(expect){
                expect(job.dateJobEnd).notToExist();
            })

            test.add("Expect job's date request to exist.", function(expect){
                expect(job.dateRequested).toExist();
            })

            test.add("Expect job's state to be 'todo'.", function(expect){
                expect(job.state).toBe('todo');
            })

            test.add("Expect job's order to be '0' (Number).", function(expect){
                expect(job.order).toBe(0);
            })

            test.add("Expect job's worker's name to be the same as the requested one.", function(expect){
                expect(job.forWorker.name).toBe(dummyData.worker.name);
            })

            test.add("Expect job's worker's number to be the same as the requested one.", function(expect){
                expect(job.forWorker.number).toBe(dummyData.worker.number);
            })

            test.add("Expect job's worker's _id to be the same as the generated one.", function(expect){
                console.log(worker);
                expect(job.forWorker._id.toString()).toBe(worker._id.toString());
            })

            test.add("Expect job's product's code to be the same as the requested one.", function(expect){
                expect(job.product.code).toBe(dummyData.product.code);
            })

            test.add("Expect job's product's description to be the same as the requested one.", function(expect){
                expect(job.product.description).toBe(dummyData.product.description);
            })

            test.add("Expect job's product's _id to be the same as the requested one.", function(expect){
                expect(job.product._id.toString()).toBe(product._id.toString());
            })
            this.fireDataEvent('validationEnded', {err: false})
        }
    }

});
4

1 に答える 1

1

テストから始める場合、「高レベル」または「統合テスト」(IT) を実行するのは常に魅力的です。「単なる」単体テストよりも自然で、より「簡単」で強力に感じられます。すでにシステム全体が稼働しているのに、それに基づいてテストを行ってみませんか?

しかし、ソフトウェア開発では常にそうであるように、IT とは、より多くの依存関係があることを意味します。これらのテストを実行するには、データベースが特定の状態にある必要があります。サーバーを実行する必要があります。ブラウザが必要になります。ネットワーキングが機能するはずです。IT の場合、システム全体を正確に定義された状態にする必要があり、システムをまさにこの状態にするためのツールが必要です。個々のテストの前にそれを行う必要があります。

問題: 各依存関係がエラーの原因です。依存関係の数が特定のポイントに達すると、そのうちの 1 つが常に壊れ、テストは失敗します。コードが壊れているからではなく、初期状態の作成が複雑すぎるためです。

これが、単体テストから実際に開始する必要がある理由です。システム内で依存関係のない最小のコンポーネントを見つけてテストします。

このアプローチの利点:

  1. 複雑さを軽減します。IT とは対照的に、テストは多くの場合、または常に成功します。
  2. テストケースは小さくなります。必要な初期状態と最終状態を理解するのに 1 時間もかかりません。
  3. セットアップがはるかに簡単になります (通常、セットアップの行はまったくないか、1 ~ 2 行あります)。
  4. 依存関係の変更によって他のテストが中断されることはありません。IT では、1 つの小さな変更が他のすべてのテストを無効にする可能性があります。
  5. 個々のコンポーネントがすべて正しく動作することがわかっていれば、残りのコードのバグは自動的に消えます。
  6. バグの修正がはるかに簡単になります。わずか 10 行のコードをテストする場合、バグはその 10 行のコードに含まれている必要があります。IT 部門を運営している場合、バグはどこにでもある可能性があります。

結論: jasmineを入手して、いくつかの単体テストを開始します。すべての単体テストがある場合、システム全体の IT を書くことははるかに簡単になります。

于 2012-09-07T11:51:42.820 に答える