So I have the following ViewModel:
using Prism.Commands;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using TrackIt.Model;
using TrackIt.UI.Event;
namespace TrackIt.UI.ViewModel
{
public class NavigationItemViewModel : ViewModelBase
{
private string _displayMember;
private IEventAggregator _eventAggregator;
private string _detailViewModelName;
public NavigationItemViewModel(int id,
IEventAggregator eventAggregator,
string detailViewModelName)
{
Id = id;
_detailViewModelName = detailViewModelName;
OpenDetailViewCommand = new DelegateCommand(OnOpenDetailViewExecute);
_eventAggregator = eventAggregator;
}
public int Id { get; }
public ICommand OpenDetailViewCommand { get; set; }
private void OnOpenDetailViewExecute()
{
_eventAggregator.GetEvent<TestEvent>()
.Publish(Id);
_eventAggregator.GetEvent<OpenDetailViewEvent>()
.Publish(
new OpenDetailViewEventArgs
{
Id = Id,
ViewModelName = _detailViewModelName
}
);
}
}
}
Thus I have an ICommand
above, that upon executing, will trigger the TestEvent
and OpenDetailViewEvent
events, with the TestEvent
having an integer argument, and the OpenDetailViewEvent
having a custom class argument OpenDetailViewEventArgs
class.
I'm testing that upon executing the command, the Publish
method of each event is called. I use Moq
to mock the GetEvent
calls. This is my code:
using Moq;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TrackIt.UI.Event;
using TrackIt.UI.ViewModel;
using Xunit;
namespace TrackIt.UITests.ViewModel
{
public class NavigationItemViewModelTests
{
[Fact]
public void ShouldPublishOpenFriendDetailViewEvent()
{
const string displayMember = "test string";
const int id = 4;
const string detailViewMemberName = nameof(FriendDetailViewModel); // Just take a random detail view
var _mockedOpenDetailViewEvent = new Mock<OpenDetailViewEvent>();
var _mockedTestEvent = new Mock<TestEvent>();
var eventAggregatorMock = new Mock<IEventAggregator>();
eventAggregatorMock
.Setup(dp => dp.GetEvent<OpenDetailViewEvent>())
.Returns(_mockedOpenDetailViewEvent.Object);
eventAggregatorMock
.Setup(dp => dp.GetEvent<TestEvent>())
.Returns(_mockedTestEvent.Object);
var _itemViewModel = new NavigationItemViewModel(id,
displayMember, eventAggregatorMock.Object, detailViewMemberName);
_itemViewModel.OpenDetailViewCommand.Execute(null);
_mockedTestEvent.Verify(e => e.Publish(id),
Times.Once);
_mockedOpenDetailViewEvent.Verify(e => e.Publish(new OpenDetailViewEventArgs { Id = id, ViewModelName = detailViewMemberName }),
Times.Once);
}
}
}
The thing is, the test passes the Verify
for TestEvent
event, but it fails for OpenDetailViewEvent
with error Expected invocation on the mock once, but was 0 times
, even though I debugged and saw the event actually published. Maybe it's because I'm supplying a custom class as its argument, while TestEvent
uses a native C# class (i.e. int
)? How to fix this?
Use an argument matcher instead since the instances can't be the same object reference in this scenario.
// ....
_mockedOpenDetailViewEvent
.Verify(
_ => _.Publish(It.Is<OpenDetailViewEventArgs>(arg => arg.Id == id && arg.ViewModelName == detailViewMemberName)),
Times.Once
);
It.Is
above is used to create a predicate to match the argument that was used to invoke the member.