23

Unit of Work の実装には、とりわけ次の方法があります。

T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();

たとえば、次のように呼びます。

var person = _uow.Single<Person>(p => p.FirstName == "Sergi");

Singleメソッドが引数で呼び出されたことを確認するにはどうすればよいFirstName == "Sergi"ですか?

私は次のことを試しましたが、役に立ちませんでした:

// direct approach 
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi"));

// comparing expressions
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi");

session.Verify(x => x
    .Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression));

それらはすべて次のエラーになります。

少なくとも 1 回はモックでの呼び出しが期待されていましたが、実行されませんでした

それをどのように行うことができるかについてのアイデアはありますか? NuGetの最新のMoqバージョン 4.0.10827.0 を使用しています。

更新: 具体例

私が見ているのは、ラムダ内で文字列リテラルを使用するたびに機能することVerifyです。変数を比較するとすぐに失敗します。適例:

// the verify
someService.GetFromType(QuestionnaireType.Objective)

session.Verify(x => x.Single<Questionnaire>(q => 
    q.Type == QuestionnaireType.Objective));


// QuestionnaireType.Objective is just a constant:
const string Objective = "objective";


// the method where it's called (FAILS):
public Questionnaire GetFromType(string type)
{
    // this will fail the Verify
    var questionnaire = _session
        .Single<Questionnaire>(q => q.Type == type);
}

// the method where it's called (PASSES):
public Questionnaire GetFromType(string type)
{
    // this will pass the Verify
    var questionnaire = _session
        .Single<Questionnaire>(q => q.Type == QuestionnaireType.Objective);
}

Verifyラムダ式でメソッド パラメータを使用するとすぐに失敗するのはなぜですか?

このテストを書く適切な方法は何でしょうか?

4

2 に答える 2

15

直接的なアプローチは私にとってはうまくいきます:

// direct approach 
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi"));

式オブジェクトは同等の式に対して true を返さないため、これは失敗します。

// comparing expressions
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi");

session.Verify(x => x
    .Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression));

理由を理解するには、次の NUnit テストを実行します。

[Test]
public void OperatorEqualEqualVerification()
{
    Expression<Func<Person, bool>> expr1 = p => p.FirstName == "Sergi";
    Expression<Func<Person, bool>> expr2 = p => p.FirstName == "Sergi";
    Assert.IsTrue(expr1.ToString() == expr2.ToString());
    Assert.IsFalse(expr1.Equals(expr2));
    Assert.IsFalse(expr1 == expr2);
    Assert.IsFalse(expr1.Body == expr2.Body);
    Assert.IsFalse(expr1.Body.Equals(expr2.Body));
}

上記のテストが示すように、式本体による比較も失敗しますが、文字列比較は機能するため、これも同様に機能します。

// even their string representations!
session.Verify(x => x
    .Single(It.Is<Expression<Func<Person, bool>>>(e => 
        e.ToString() == expression.ToString()));

そして、これも機能する武器庫に追加できるもう 1 つのテスト スタイルです。

[Test]
public void CallbackVerification()
{
    Expression<Func<Person, bool>> actualExpression = null;
    var mockUow = new Mock<IUnitOfWork>();
    mockUow
        .Setup(u => u.Single<Person>(It.IsAny<Expression<Func<Person, bool>>>()))
        .Callback( (Expression<Func<Person,bool>> x) => actualExpression = x);
    var uow = mockUow.Object;
    uow.Single<Person>(p => p.FirstName == "Sergi");

    Expression<Func<Person, bool>> expectedExpression = p => p.FirstName == "Sergi";

    Assert.AreEqual(expectedExpression.ToString(), actualExpression.ToString());
}

失敗してはならない多くのテスト ケースがあるため、別の問題が発生している可能性があります。

更新:更新ごとに、次の設定と式を検討してください。

string normal_type = "NORMAL";
// PersonConstants is a static class with NORMAL_TYPE defined as follows:
// public const string NORMAL_TYPE = "NORMAL";
Expression<Func<Person, bool>> expr1 = p => p.Type == normal_type;
Expression<Func<Person, bool>> expr2 = p => p.Type == PersonConstants.NORMAL_TYPE;

1 つの式は、それを含むメソッドのインスタンス変数を参照します。もう 1 つは、静的クラスの const メンバーを参照する式を表します。実行時に変数に割り当てられる値に関係なく、この 2 つは異なる式です。ただし、string normal_typeが変更された場合、式は式の右側のconst string normal_type各参照 a と同じになります。const

于 2011-07-11T16:36:30.390 に答える
1

また、パラメーター式を期待される式と比較する別のアプローチも共有したいと思います。StackOverflow で「式の比較方法」を検索したところ、次の記事にたどり着きました。

その後、このdb4o.netのSubversion リポジトリに誘導されました。彼らのプロジェクトの 1 つである namespaceには、 という名前のクラスが含まれています。このプロジェクトをリポジトリからチェックアウトし、コンパイル、ビルドして、自分のプロジェクトで使用する DLL を作成することができました。Db4objects.Db4o.Linq.ExpressionsExpressionEqualityComparer

を使用すると、呼び出しを次のようにExpressionEqualityComparer変更できます。Verify

session.Verify(x => x .Single(It.Is<Expression<Func<Person, bool>>>(e => new ExpressionEqualityComparer().Equals(e, expression))));

最終的に、この場合、ExpressionEqualityComparerと のToString()手法は両方とも true を返します (ToString最も可能性が高いのは高速で、速度はテストされていません)。個人的には、より自己文書化されており、設計意図をよりよく反映していると感じるため、比較アプローチを好みます (ToString 出力の文字列比較ではなく、式オブジェクトを比較します)。

注: 私はまだこのプロジェクトで db4o.net ライセンス ファイルを探していますが、とにかくコードを変更していません。今... ;-)

于 2014-06-10T18:21:22.013 に答える