当服务传递给基类的泛型方法时,不会调用Moq'ed服务方法

本文关键字:服务 Moq 调用 方法 ed 基类 泛型方法 | 更新日期: 2023-09-27 17:54:39

我有一个管理列表项的基类的泛型方法:

public abstract class BaseViewModelHandler<T> : BaseLogger, IViewModelHandler<T>
    where T : IViewModel
{
    public abstract void Handle(T viewModel);
    protected ISet<TE> ManageListItems<TE>(int[] selectedItemIds, ISet<TE> list, IService<TE> service)
        where TE : IEntity
    {
        try
        {
... param checking and code to remove unwanted items not included for brevity
            if (selectedItemIds.Any())
            {
                var itemIdsToAdd = selectedItemIds.Where(id => list.All(x => x.Id != id)).ToList();
                if (itemIdsToAdd.Any())
                {
                    foreach (var id in itemIdsToAdd)
                    {
                        var item = service.GetById(id);
                        list.Add(item);
                    }
                }
            }
            return list;
        }
...catch block removed for brevity
    }
}

我有一个继承这个基类的类。

public class ConcreteViewModelHandler : BaseViewModelHandler<ConcreteViewModel>
{
    private readonly IMyService _myService;
    private readonly IMyListItemsService _myListItemsService
    public ConcreteViewModelHandler (IMyService myService, IMyListItemsService myListItemsService)
    {
        _myService = myService;
        _myListItemsService = myListItemsService
    }
    public override void Handle(ConcreteViewModel viewModel)
    {
        try
        {
            var myEntity = viewModel.Id.HasValue
                               ? _myService.GetById(viewModel.Id.Value)
                               : new MyEntity();
            myEntity.ListToManage = ManageListItems(viewModel.SelectedItemIds, myEntity.ListToManage, _myListItemsService);
...create/update removed for brevity
        }
...catch block removed for brevity
    }
}

我正在尝试测试Handle方法。在我的测试中,我模拟了该服务,并设置了'GetById'方法来返回我的类

的新实例
_myListItemsServiceMock = new Mock<IMyListItemsService>();
_myListItemsServiceMock
      .Setup(s => s.GetById(It.IsAny<int>()))
      .Returns(new MyListItem{ Id : 1});

我的测试没有通过,当我逐步执行代码时,在基类中调用service.GetById(id);返回null。这是我正确使用Moq的第一个项目,所以我担心我对框架的缺乏经验会让我错过一些东西。

任何帮助都将是非常感激的。

按要求添加TestFixture…

[TestFixture]
public class ConcreteViewModelHandlerTestFixture
{
    private Mock<IMyService> _myServiceMock;
    private Mock<IMyListItemsService> _myListItemsServiceMock;
    #region Test Data
    private readonly ConcreteViewModel _viewModel = new ConcreteViewModel
    {
        Id = 1,
    };
    #endregion
    [SetUp]
    public void SetUp()
    {
        _myServiceMock = new Mock<IMyService>();
        _myServiceMock
            .Setup(s => s.GetById(It.IsAny<int>()))
            .Returns(new MyEntity { Id: 1});
        _myListItemsServiceMock = new Mock<IMyListItemsService>();
        _myListItemsServiceMock
            .Setup(s => s.GetById(It.IsAny<int>()))
            .Returns(new MyListItem{ Id : 1});
    }

    [Test]
    public void _the_handle_method_works()
    {
        //arrange
        var handler = new ConcreteViewModelHandler(_myServiceMock.Object, _myListItemsServiceMock.Object);
        // act
        handler.Handle(_viewModel);
        // assert
        // no assertions yet as the code falls over
    }
}

根据@Quinton Bernhardt的要求添加更多细节

接口:

public interface IEntity
{
    int Id { get; }
    //Guid Guid { get; }
    int UpdateId { get; set; }
}

基类:

public abstract class BaseEntity : IEntity
{
    protected BaseEntity()
    {
    }
    protected BaseEntity(int id)
    {
        Id = id;
    }
    public virtual int Id { get; protected internal set; }
    public virtual int UpdateId { get; set; }
}

和MyListItem类

public class MyLIstitem : BaseEntity
{
    public MyLIstitem ()
    {
    }
    public MyLIstitem (int id)
        : base(id)
    {
    }

    public virtual string Name { get; set; }
    public virtual string Value { get; set; }
}

当服务传递给基类的泛型方法时,不会调用Moq'ed服务方法

您的问题描述如下:

我的测试没有通过,当我遍历调用的代码时service.GetById (id);在我的基类中返回null

所以一定是对ManageListItems<TE>()的调用失败了:

var item = service.GetById(id);

希望我是正确的,因为这是一个假设[使用提供的信息]。

IMyListItemService是否实现了IService<IEntity> ?因为你的代码暗示了它。

我能看到的唯一奇怪的是ManageListItems<TE>()的最后一个参数期望一个类型为IService<TE> where TE is IEntity的参数,该参数用于调用service.GetById(id)

protected ISet<TE> ManageListItems<TE>(int[] selectedItemIds, ISet<TE> list, IService<TE> service)

留在我身边…

但是您从具体类中提供给该方法的对象是IMyListItemsService类型的,可以从以下Handle方法中看出:

myEntity.ListToManage = ManageListItems(viewModel.SelectedItemIds, myEntity.ListToManage, _myListItemsService);

我认为正在发生的事情… GetById的设置应该在IService上而不是IMyListItemsService

在列表服务上设置GetById时,而不是这样:

    _myListItemsServiceMock
        .Setup(s => s.GetById(It.IsAny<int>()))
        .Returns(new IMyListItem{ Id : 1});

    _myListItemsServiceMock.As<IService>()
        .Setup(s => s.GetById(It.IsAny<int>()))
        .Returns(new IMyListItem{ Id : 1});

    _myListItemsServiceMock.As<IService<IEntity>>()
        .Setup(s => s.GetById(It.IsAny<int>()))
        .Returns(new IMyListItem{ Id : 1});