2

メソッドのテストでインターフェイスの値を設定する方法について、以前に質問しました 。プロジェクトへの Moq フレームワークの実装に成功し、テストは正常に実行されます。

これは私が紹介したサンプルコードです:

public void PostEvent(
            eVtCompId inSenderComponentId, 
            eVtEvtId inEventId, 
            long inEventReference, 
            IF_SerializableData inEventData)
{
    if(mEventMap.ContainsKey(inEventId))
    {
        mEventMap[inEventId](inSenderComponentId, inEventReference, inEventData);
    }
}

ここには 4 つのパラメーターがあります。1 番目: 列挙型、2 番目: 別の列挙型、3 番目: long、4 番目: インターフェイスです。ただし、4 番目のパラメーター (インターフェイス) はインターフェイスではなく、インターフェイスに対するものであると誤解されていましたreference

したがって、次のようになります。

public void PostEvent(
       eVtCompId inSenderComponentId, 
       eVtEvtId inEventId, 
       long inEventReference, 
       ref IF_SerializableData inEventData)

私に与えられたサンプルMoqテストコード(これはこれです)...

var serializable = new Mock<IF_SerializableData>();
target.PostEvent(..., serializable.Object);

...うまくいきません。試してみましref serializable.Objectたが、ref パラメーターがオブジェクトではなく変数への参照を予期しているというエラーが表示されるため、まだ機能しません。

これを適切にテストする方法に関するヒントや例はありますか?

4

1 に答える 1

3

として渡すことができるようにObject、モックからローカル変数に参照をコピーする必要があります。serializableref

IF_SerializableData localRef = serializable.Object;
target.PostEvent(..., ref localRef);

ref Serializable.Objectプロパティであるため、渡すことはできません。「出力」または「参照」パラメーターとしてプロパティを渡すことは可能ですか?も参照してください。なぜこれが当てはまるのかについての優れた議論と、他のリンクのソースを提供します.

私の説明

これは最終的に、プロパティが変数ではないためです。読み取り/書き込みプロパティは、変数のような機能を提供するペアgetsetアクセサー メソッドですが、重要なのはget、プロパティを使用すると、その変数に参照型がある場合でも、常に基になる変数のコピーを取得することです。

そう:

public class MyClass {
  private object _property;
  public object Property {
    get { return _property; } //<-- _property reference copied on to stack & returned
                              //    here as a new variable.  Therefore a ref
                              //    on that is effectively meaningless.
                              //    for a ref to be possible you'd need a pointer 
                              //    to the _property variable (in C++ terms)
    set { _property = value; }
  }
}

この例では、メソッドに渡すことができref MyClass.Propertyたとしても、スタック上の一時変数への参照を渡すことになるため、意味がありません。つまり、Property get accessor; it would not be passing the property by reference. So C# doesn't allow it, even though it could, because it would imply thatProperty` によって返される参照のコピーはメソッドによって変更できますそれは単にできません。

したがって、スタックからその値をキャプチャしてローカル変数にコピーする必要があるのはなぜですか。refここで-メソッドによって設定された新しい値があなたに表示されるようにするには、そのプロパティをローカル変数の値に再度Mock<T>設定する必要があることに注意してくださいObject(可能であれば-Moqは使用しませんが、モックは不変であると想定しています) )。

C# がこの方法で自動的に処理する必要があるかどうかについては、多くの議論がありましたref Property(リンク先の前述の SO を参照してください)。私の考えでref Derivedは、互換性がないことに似ていref Baseます-はい、言語がこれを自動的に処理できる方法がありますが、そうすべきですか? 私の考えでは、いいえ。私はそれに不満を感じますか?もちろん、そうです。しかし、実際に修正する必要があるアーキテクチャの弱点が浮き彫りになっていることがよくあります (たとえば、戻り値の方が優れている可能性が高いパラメータrefやパラメータに依存しているなど)。out

C# でプロパティを参照渡しできるようにする唯一の方法は、get アクセサーと set アクセサーをターゲット メソッドに渡すことです。これはまったく互換性がありませんref(これは単なるメモリの場所であるため)。

テイスターとして、次のようなメソッドを作成する必要があります。

 public static void MyUglyRefMethod(Func<object> refGet, Action<object> refSet)
 {
   var read = refGet();
   var newValue = new object();
   refSet(newValue);
 }

これにより、次のようなセマンティクスを提供できるようになりました。refMyClass

 MyClass a = new MyClass();
 MyUglyRefMethod(() => a.Property, (newValue) => a.Property = newValue);
 Assert.IsNotNull(a.Property);

しかし、それは単に地獄のように醜いです。

-を取るメソッドを作成する方が簡単ref MyClassで、任意のプロパティに直接書き込むことができます。

于 2012-12-11T08:53:12.367 に答える