1

以下のモジュールがあります。テーブルからユーザー ID のリストを返します。ID は正規表現と一致します。

public sealed class UserIdListRetriever : IUserIdListRetriever
{
    private readonly EntityFrameworkClass _databaseConnection;

    public UserIdListRetriever(EntityFrameworkClass databaseConnection)
    {
        _databaseConnection = databaseConnection;
    }

    public IEnumerable<string> Retrieve()
    {
        var salesAgents = _databaseConnection
            .tblAccounts
            .Select(account => account.UserId)
            .Distinct();

        var regex = new Regex(@"(?<=\\)(.*?)(?=\:)");

        return (from agent in salesAgents
                .AsEnumerable()
                select regex.Match(agent)
                into match
                where match.Success
                select match.Value.ToUpper())
                .OrderBy(match => match);
    }
}

そして、ここにインターフェースがあります:

public interface IUserIdListRetriever
{
    IEnumerable<string> Retrieve();
}

実装ではなく動作をテストする必要があることを読み続けていますが、ここで気になるのは、クラスがユーザー ID の正確なリストを返すかどうかです。

IUserIdListRetriever のモック実装を作成し、単体テストで null ではない文字列の IEnumerable を返すことをアサートすることもできますが、それでは LINQ が正しいかどうか、または私の正規表現は正しいですが、それほど役に立ちません。

これらがここで重要な2つのことであるかのように感じます(LINQが正しいかどうか、および正規表現が正しいかどうか)。最終的には次のようなテストクラスになります。

using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
etc etc

namespace myNamespaceTests
{
    [TestClass]
    public class UserIdListRetrieverTests
    {
        [TestMethod]
        public void UserIdListRetrieverReturnsAccurateInformation()
        {
            var databaseConnection = 
                new EntityFrameworkClass("connection;string;");

            var userIdListRetriever = new UserIdListRetriever(databaseConnection );

            var userIds = userIdListRetriever.Retrieve();

            /*
             * I put a breakpoint here, 
             * and run the same query in SQL Management studio 
             * to make sure I have the same results
            */
             Assert.IsTrue(userIds.Any());
        }
    }
}

これは非常に間違っているように感じますが、私の観点からは、このモジュールが自分のやりたいことを実行しているかどうかをすばやく (それほど速くはありませんが) テストできるため、これが最も便利だと思います。

私はこのようなモジュールをたくさん持っており、私のコードはまだモジュール化されていてテスト可能ですが、単体テストを手動で実行し、それぞれをステップ実行し、データベースに対して手動でクエリを実行して検証するのに少し時間を費やす場合にのみ、テストが役立つと思います私のデータ検索モジュールが私に返してくれる情報は、私が期待しているものです。この後、コードベース内のすべてのモジュールが自分のやりたいことを実行していると自信を持って言えます。

私はこのように働いている人を他に知りませんが、これは通常悪い兆候です (私が間違っているのでしょうか、それとも他の人が間違っているのでしょうか?)。より知識のある誰かが、ここで私がどこで間違っているのかを説明し、上記のようなクラスをテストする方法を説明できますか?テストをすばやく実行でき、それらのテストは自動化されますが、各モジュールには自信を持って意図した動作?

ありがとう

4

2 に答える 2

2

私は通常、データベースが関係する場合、それは単体テストではないと考えています。そうは言っても、私はこの同じ問題を数年間調べてきましたが、データ検索ステートメントをテストするためのより洗練されたソリューションを提供することはできません.

このコードは、単一責任の原則に従っていないことに注意してください。つまり、EF ソースからデータを取得し、さらにフィルター処理します。できることは、このコードを 2 つの部分に分割することです。1 つはリストを取得するためのもので、もう 1 つは正規表現に一致する文字列のリストを調べるためのものです。次に、単体テストを簡単にセットアップして、正規表現が期待どおりに機能していることを確認できます。

于 2013-10-14T12:24:37.860 に答える
2

This approach leads to Integration tests not Unit tests. What if you run your Unit tests on a Build server where no connections are available to the Database.

First you must under stand if you're using the actual resources then This would be an Integration test not Unit test.

So if you want to test the database connection integrity you're doing right. But if you just want to test your filter logic. Then you must refactor your method Retrieve() into two parts.

part i) Returns the exact results returned from database.

part ii) Test filter operation on result.

This way you can mock your returned result from DB. Then test the method of filterning to ensure that on a given DB result it's working fine.

e.g.

        public IEnumerable<string> Retrieve()
        {
            return _databaseConnection.tblAccounts.Select(account => account.UserId).Distinct();
        }

        public IEnumerable<string> GetMatchingItems(IEnumerable<string> salesAgents)
        {
            var regex = new Regex(@"(?<=\\)(.*?)(?=\:)");

            return (from agent in salesAgents
                    .AsEnumerable()
                    select regex.Match(agent)
                        into match
                        where match.Success
                        select match.Value.ToUpper())
                    .OrderBy(match => match);
        }
于 2013-10-14T12:19:37.273 に答える