4

いくつかのデフォルトの実装を提供する基本クラスがありますINotifyPropertyChanged(このクラスは他の多くのクラスで使用され、簡単に変更することはできません)。

public class ObservableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // this is virtual so derived classes can override it (rarely used, but it is used)
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

これで、インターフェイスと、そのインターフェイスから派生しObservableBaseて実装する抽象基本クラスができ、いくつかのデフォルトの実装 (主にプロパティ用) が提供されます。

public interface INamedTrigger
{
    string Name { get; }
    void Execute();
}

public abstract class ObservableNamedTriggerBase : ObservableBase, INamedTrigger
{
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set { _Name = value; OnPropertyChanged("Name"); }
    }

    public abstract void Execute();
}

ObservableNamedTriggerBaseここで、 (NUnit と RhinoMocks を使用して)の既定の実装を単体テストしたいと思います。

[TestFixture]
public class ObservableNamedTriggerBaseTest
{
    [Test]
    public void TestNameChangeRaisesPropertyChanged()
    {
        var prop = "";
        var mocks = new MockRepository();
        var namedBase = mocks.PartialMock<ObservableNamedTriggerBase>();
        namedBase.PropertyChanged += (s, e) => prop = e.PropertyName;
        namedBase.Name = "Foo";
        Assert.AreEqual("Name", prop);
    }
}

OnPropertyChanged残念ながら、Rhino がからの仮想メソッドをオーバーライドしているように見えるため、このテストは失敗しますObservableBase

This SO questionRhino docsPartialMockは、これを行うべきではないことを示しています。一方、このSO の質問に対する回答は、Rhino がモックの種類に関係なく常に仮想メソッドをオーバーライドすることを示しています。

では、ドキュメントは間違っていますか?そして、これを正しくテストするにはどうすればよいですか?

更新: 抽象メソッドだけのダミー実装を提供する独自のモック クラスを作成すると、テストはパスしますが、Rhino モックを使用して、正確にそれを行う作業を節約したいと思います。

4

4 に答える 4

2

どのバージョンを使用しているかはわかりませんが、RR ( Record-Replay ) 構文の使用法と最近の AAA ( Arrange-Act-Assert ) を混在させているようです。基本的に、これを行う:

var repo = new MockRepository();
var mock = repo.PartialMock<ObservableNamedTriggerBase>();

少なくともこれを行う必要があります。

repo.ReplayAll();

これがないと、モックの誤動作が発生します (repo.Record()期待/スタブを設定している場合は、への呼び出しが必要になる場合があります)。最新の構文が利用可能であることを考えると、これは不必要な作業です ( Rhino 3.5以降 ):

// no repository needed at all
var mock = MockRepository.GeneratePartialMock<ObservableNamedTriggerBase>();

の新しい静的メソッドMockRepositoryは、内部で記録と再生のセットアップを処理します。

于 2013-01-10T09:45:51.630 に答える
1

アイデアは、メソッドがオーバーライドできないテスト サブクラスを作成することです。

public abstract class TestingObservableNamedTriggerBase : ObservableNamedTriggerBase {
  protected override sealed void OnPropertyChanged(string propertyName) {
    base.OnPropertyChanged(propertyName);
  }
}

そして、このサブクラスでテストします。

これが機能するかどうかはテストしていませんが...

于 2013-01-10T04:00:05.507 に答える
0

Rhinomocks のCallOriginalMethodメソッドを使用して、元のメソッドを呼び出すことができます。

namedBase.Expect(x => x.OnPropertyChanged(Arg<string>.Is.Anything))
         .CallOriginalMethod(OriginalCallOptions.NoExpectation);

OnPropertyChangedテスト対象のクラスにテスト アセンブリの他のアセンブリが含まれている場合は、メソッドを作成し、テスト アセンブリprotected internalに追加する必要がある場合がありますInternalVisibleToAttribute

また、すでにご存知のように、InternalVisibleToAttribute("DynamicProxyGenAssembly2")内部型をモックに追加します。

于 2013-01-10T05:16:43.707 に答える