3

レガシー プロジェクトをテスト対象にしようとしています。コードは一般的にテストできるように書かれていますが、サードパーティの依存関係の一部はそうではありませんでした。次のような単体テストの方法を頭に入れようとしています。

class InsightEmailJob : NHibernateJob
{
    public IInsightEmailService InsightEmailService { get; set; }
    public IReportService ReportService { get; set; }
    public ITemplatedNotifier TemplatedNotifier { get; set; }
    public string ReplyEmail { get; set; }
    public string ReplyName { get; set; }

    public InsightEmailJob(ISession session,
        ILog log,
        IInsightEmailService insightEmailService,
        IReportService reportService,
        ITemplatedNotifier templatedNotifier,
        SystemReplyEmailSpec systemReplyEmailSpec)
        : base(session, log)
    {
        InsightEmailService = insightEmailService;
        ReportService = reportService;
        TemplatedNotifier = templatedNotifier;
        ReplyEmail = systemReplyEmailSpec.ReplyEmail;
        ReplyName = systemReplyEmailSpec.ReplyName;
    }

    public int AccountID{ get; set; }
    private Account mAccount;

    public Account Account
    {
        get
        {
            if (this.mAccount == null)
            {
                mAccount = this.InsightEmailService.Get<Account>(AccountID);
            }
            return mAccount;
        }
    }


    protected override void DoWork(JobExecutionContext context)
    {
        var insightEmail = InsightEmailService.FindAndIncrementEmailForAccount(Account);
        var report = ReportService.LoadMultiReportByName(insightEmail.ReportName);
        var reportData = ReportService.Execute(report, new ParameterValuesDictionary(Account, DateTime.Now.AddDays(-7), DateTime.Now, 0));
        var templateData = new Hashtable {{"data", reportData}, {"account", Account}};
        foreach (var u in Account.Users.Where(x => x.Notify))
        {
            TemplatedNotifier.Send(u.UserName, ReplyName, ReplyEmail, insightEmail.TemplateName, templateData);
        }
    }
}

インターフェイスの代わりにモックまたはスタブを使用して渡すことを提案する人が多いことは理解していますが、これが実際にどのように役立つかについては少し混乱しています。これは、適切なメソッドが呼び出されることを保証するだけのようですが、これはやや空虚であり、ジョブの実装とあまりにも結びつきすぎて、本当に有効なテストにはなりません。最終的に問題になるのは、値を返さず、実際に副作用を引き起こすだけのものを、あなたが言うように実装されていることをテストするだけでなく、どのように単体テストするのですか?

4

2 に答える 2

1

単体テストは、実装が正しく機能することを証明するために作成されます。テスト コードが複雑になりすぎてモックが難しくなっている場合は、実装コードも複雑になり、理解するのも難しくなっている可能性があります。

依存関係をモックする作業が多すぎると判断した場合は、設計を再検討し、より単純な形式にリファクタリングすることを目指す必要があります。

コンストラクターを見るだけで、おそらくあまりにも多くの作業を行っていることがわかります。6 つの依存関係があり、有効な単体テストを作成するには、それらすべてをモックする必要があります。NHibernate セッション、いくつかのレポート サービスを処理し、電子メールを送信する必要があるため、ここでは十分な抽象化がないと思います。

リポジトリ パターンは、データ アクセス コードを抽象化するための一般的なパターンです。また、メール送信部分を別のクラスに移動し、ここでそのインターフェイスを使用する必要があります。

戻り値を持たないメソッドをモックするのはとても簡単です。これらのメソッド呼び出しをモックすることで、クラスが外部依存関係を正しく使用していることを証明できます。パラメーター値のアサートと、コードを検証するために呼び出される回数を記述できます。

とにかく、これはMoqでメソッドをモックする方法の例です

insightEmailService.Setup(mock => mock.FindAndIncrementEmailForAccount(It.IsAny<Account>()))
                   .Verifiable();
于 2013-05-01T18:28:16.440 に答える
0

ユニットテストを行うときは、ユニットをテストしているだけです。これは、特定の外部依存関係の下で、ユニットがどのようになっているのかを意味します (例: 他のサービスからメソッドを呼び出すメソッド)。したがって、テスト中のコードが正しく動作するかどうか、外部依存関係のさまざまな状態を確認する必要があります。

何も返さないメソッドについては、これを確認する方法がいくつかあります

  1. たとえば Moq などの Mocking フレームワークを使用している場合は、Verify を使用して、外部メソッドが適切なパラメーターで呼び出されることを確認できます。
  2. コールバックを使用して外部メソッドに渡されたものを確認できます (moq には適切なコールバック メカニズムがあります)。
于 2013-05-01T18:26:25.660 に答える