Moqを使用したイベント登録の検証
-
07-07-2019 - |
質問
MVPパターンを実装しようとしているasp.net(クラシック)アプリケーションを開発していますこの例を使用。プレゼンターのユニットテストを試みて、次のパターンを使用すると、擬似コードは次のようになります
//base view interface
public interface IView
{
event EventHandler Init;
event EventHandler Load;
bool IsPostBack { get; }
void DataBind();
bool IsValid { get;}
}
//presenter psuedo code
public class SomePresenter
{
public SomePresenter(ISomeDomainService service, IView someView)
{
...
//HOW DO WE TEST/VERIFY THAT THIS REGISTRATION OCCURS?
someView.Init += OnInit;
someView.Load += OnLoad;
}
}
...
//consuming code that exercises the above code, that needs to be tested
var presenter = new SomePresenter(someDomainService, someView);
プレゼンターが期待どおりに動作していること、つまりInitイベントとLoadイベントに登録していることを確認するにはどうすればよいですか?これは、Rhinoを使用する Phil Haackの例で簡単に実行できます。モック...
[Test]
public void VerifyAttachesToViewEvents()
{
viewMock.Load += null;
LastCall.IgnoreArguments();
viewMock.PostSaved += null;
LastCall.IgnoreArguments();
mocks.ReplayAll();
new PostEditController(viewMock,
this.dataServiceMock);
mocks.VerifyAll();
}
... MOQを使用してこれを行うにはどうすればよいですか
解決
この機能は現在利用できないようです moqではありますが、将来のバージョンで表示される可能性があります(4.0.812.4ベータ版で見ましたが、存在しないようです)。
質問をする価値があるかもしれません、<!> quot;なぜSomePresenter
はビューのLoad
およびInit
イベントにサブスクライブする必要があるのですか?<!> quot;これはおそらく、Raise
クラスがこれらのイベントに応答する必要があるためです。そのため、Mock<IView>
で<=>メソッドを使用して<=>および<=>イベントを発生させ、<=>がそれらに応じて正しいことを行ったことをアサートする方がよい場合があります。
他のヒント
#Dilipには遅すぎるかもしれませんが、この答えは同じことをしようとしている人にとって役立つことがあります。 これがテストクラスです
public delegate void SubscriptionHandler<T>(string name, T handler);
public class SomePresenterTest
{
[Test]
public void Subscription_Test()
{
var someServiceMock = new Mock<ISomeDomainService>();
var viewMock = new Mock<IView>();
//Setup your viewMock here
var someView = new FakeView(viewMock.Object);
EventHandler initHandler = null;
someView.Subscription += (n, h) => { if ((nameof(someView.Init)).Equals(n)) initHandler=h; };
Assert.IsNull(initHandler);
var presenter = new SomePresenter(someServiceMock.Object, someView);
Assert.IsNotNull(initHandler);
Assert.AreEqual("OnInit", initHandler.Method?.Name);
}
}
FakeView は次のように実装されたデコレータです(Events:Init / Load {add; remove}に注意してください):
public class FakeView : IView
{
public event SubscriptionHandler<EventHandler> Subscription;
public event SubscriptionHandler<EventHandler> Unsubscription;
private IView _view;
public FakeView(IView view)
{
Assert.IsNotNull(view);
_view = view;
}
public bool IsPostBack => _view.IsPostBack;
public bool IsValid => _view.IsValid;
public event EventHandler Init
{
add
{
Subscription?.Invoke(nameof(Init), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Init), value);
_view.Init -= value;
}
}
public event EventHandler Load
{
add
{
Subscription?.Invoke(nameof(Load), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Load), value);
_view.Init -= value;
}
}
public void DataBind()
{
_view.DataBind();
}
}
この質問に少し時間を費やしました。プロジェクトで使用しているソリューションは次のとおりです。
単体テスト:
// Arrange
TestedObject.Setup(x => x.OnEvent1());
TestedObject.Setup(x => x.OnEvent2());
// Act
TestedObject.Object.SubscribeEvents();
TestedObject.Raise(x => x.Event1 += null);
TestedObject.Raise(x => x.Event2 += null);
// Assert
TestedObject.Verify(x => x.OnEvent1(), Times.Once());
TestedObject.Verify(x => x.OnEvent2(), Times.Once());
テスト済みのメソッド:
this.Event1 += OnEvent1;
this.Event2 += OnEvent2;
そのため、テストするメソッドを呼び出した後、最初にイベントを割り当てるメソッドをモックし、最後にすべてのサブスクライブされたイベントを発生させる必要があります。イベントが本当にサブスクライブされている場合、割り当てられたメソッドが呼び出されているかどうかをMoqで確認できます。
GLHF!