web-dev-qa-db-ja.com

統合テストの代わりに(または統合テストとともに)例の単体テストを作成する理由

リポジトリ層にリポジトリ機能があります。私はデータアクセスとしてsequelizeを使用しています。関数のテストを記述します。

ここに私が英語で欲しい論理があります:

  • 私の関数は、電子メールとパスワードを使用してデータベースにユーザーを保存する必要があります
  • 私の関数は、作成したユーザーのオブジェクト表現を返す必要があります。

ロジックについては、以下のコードを記述します。

const UserModel = require('../models/user');

exports.create = async (email, password) => {
    const createdUser = await UserModel.create({
        email,
        password
    });

    return createdUser.toJSON();
};

だから、私は統合テストを書くつもりです。以下のようにいくつかのテストを書きます。

const userRepository = require('./repositories/user');
const userModel = require('./model/user');
const chai = require('chai');

it('should create a user by using the correct email and password', async () => {
    const email = '[email protected]';
    const password = 'test@Pass123';

    const createdUser = await userRepository.create(email, password);

    const userInDb = userModel.findOne(
        {
            id = createdUser.id
        }
    );

    chai.expect(userInDb.email).to.be.equal(email);
    chai.expect(userInDb.password).to.be.equal(password);
});

it('should return object representation of created user', async () => {
    const email = '[email protected]';
    const password = 'test@Pass123';

    const createdUser = await userRepository.create(email, password);

    chai.expect(typeof userInDb).to.be.equal('object');
});

だから私はいくつかの質問があります。

  1. テストは十分ではありませんか?そのための単体テストを作成する必要がありますか?または、統合テストの有無にかかわらず、私のメソッドの単体テストを行う利点は何ですか?.

  2. 統合テストと単体テストを一緒に作成する必要がありますか?

  3. メソッドの単体テストを作成するにはどうすればよいですか?

    また、何かが間違っているようです。

  4. 私のテストは互いに依存しています。たとえば、オブジェクトを返す必要があるテストが失敗した場合、他のテストも失敗する可能性があります。私が返す結果は最初のテストのオブジェクトになるからです。

  5. 私のテストは、使用するパッケージによって異なります。私のリポジトリメソッドでは、ロジックにSequelizeを使用しています。ただし、Sequelize ORMを別のORMに変更した場合。テストも変更する必要があります。

2
Mansur

テストは十分ではありませんか?そのための単体テストを作成する必要がありますか?

直観的に言えば、質問は有効なようです。統合テストでは、単体テストが機能していることが既に確認されています。

その考え方の問題は、「小規模ではありますが」「アプリケーションはそのまま正常に動作するので、なぜその一部をテストする必要があるのか​​」と考えるのと同じ原理であるということです。

テストを書くとき、どの部分が機能しているかに興味がなく、どの部分に興味があるか機能していません

統合テストは、本質的に複数のコンポーネント/レイヤーで実行されるテストです。失敗した統合テストでは、これらのパーツのどれが壊れたかを通知できません。すべてが機能しているわけではありません。問題をいくぶん絞り込みますが、単体テストほどではありません。

そのため、はい、統合テストがある場合でも、単体テストは適切です。単体テストでは、失敗したコンポーネントに正確にフラグを立てることができます。統合テストでは、テスト結果が本質的に複数のコンポーネントの結果に結び付けられているため、そのレベルの精度は得られません。

単体テストが必要ですか?まあ、それはあなたの裁量次第です(またはあなたのプロジェクトリーダーのそれ)。それには利点があります(デバッグの問題を削減)、欠点(コストと労力)があります。それが正味であるかどうかは、コスト/利益分析が必要です。

統合テストと単体テストを一緒に作成する必要がありますか?

同時に、または同じテストスイートで「一緒に」書くことを意味する場合は、できません。これらは完全に分離することができますが、一般的には独自のプロジェクトに分離することをお勧めします。それらを精神的に分離しておくための方法として、また、一方のスイートをもう一方のスイートなしで実行する能力を持つ方法として。

ただし、必要に応じて、それらを同じスイートに保持しても技術的な問題はありません。

メソッドの単体テストを作成するにはどうすればよいですか?

私はJavaScript開発者ではないので、正確なコードを提供することはできません。しかし、単体テストへの一般的なアプローチはモックされた依存関係を使用することです。

あなたの場合、これは、_exports.create_をテストするときに、UserModelをモックしたUserModelに交換することを意味します。テストするオブジェクト。

状況をエミュレートし、うまくいけば一般的な始まりを説明する小さなC#の例:

_// Mock a dependency
var mockedUserModel = NSubstitute.For<UserModel>();

// When create() is called with any valid string values
// then we tell it to return John Doe as its return value.
mockedUserModel
    .create(Arg.Any<string>(), Arg.Any<string>())
    .Returns(new User() { Firstname = "John", LastName = "Doe" });

// Inject the mock into the real test subject
var exports = new Exports(mockedUserModel);

// Call the real method, which will unknowingly rely on a fake (mocked) dependency
var result = exports.create("[email protected]", "barbaz");

// Confirm that the result matches your expectations
result.Should().Be("{ 'FirstName': 'John', 'LastName': 'Doe' }");
_

ユニットテストの最初は、依存関係から特定の動作が与えられると(依存関係をモックすることで保証します)、テストサブジェクトはそれに応じて動作します(この場合は、JSON文字列にシリアル化します)。

これは実際のデータベースの相互作用を必要としないため、統合テストではなく単体テストです。

私のテストは互いに依存しています。たとえば、オブジェクトを返す必要があるテストが失敗した場合、他のテストも失敗する可能性があります。

まったく問題ありません。一部のバグは、アプリケーションの複数の動作に影響を与える傾向があり、これは通常、複数の異なるテストが失敗することとして現れます。

時々、ユニットテストはお互いにフォローアップします。入力検証の正しい使用を確認する単体テストと、オブジェクトが格納されていることを確認する単体テスト。論理的には、2番目のテストは、入力検証自体も合格した場合にのみ合格できます。

それは直感的に1つのように感じられますが、それは危険信号ではありません。

create()およびupdate()メソッドがあり、どちらも戻り値をJSONにシリアル化する場合を想像してください。このJSONシリアライゼーションは再利用することをお勧めします。 JSONシリアル化で問題が発生した場合、これらのテストは両方とも失敗します。これは、グッドプラクティスの実装の論理的な帰結にすぎません。

私のテストは、使用するパッケージによって異なります。私のリポジトリメソッドでは、ロジックにSequelizeを使用しています。ただし、Sequelize ORMを別のORMに変更した場合。テストも変更する必要があります。

単体テストには、このパッケージの依存関係はありません。

統合テストはそうなるでしょう。これは、統合テストが使用されている技術スタック全体に触れるよりも論理的な結果です。そのスタックが変更された場合、テストもそれに応じて変更する必要があります。これは、契約/署名が変更された場合と同じです。このような変更は、変更されたコードに依存するテストでも発生する必要があります。

2
Flater