C# Moq返回类型IEnumerable作为列表返回

C# Moq返回类型IEnumerable作为列表返回,c#,unit-testing,.net-core,moq,C#,Unit Testing,.net Core,Moq,我无法让Moq从存储库方法返回IEnumerable类型 更新-1 我希望我只是错过了一些东西,但是,按照要求,这里是已经到位的完整实现 断言objResult.Value属于IEnumerable类型是失败的 存储库界面 public interface IRepository { Task<IEnumerable<T>> GetListAsync<T>(string storedProcedure, object template); T

我无法让Moq从存储库方法返回
IEnumerable
类型

更新-1

我希望我只是错过了一些东西,但是,按照要求,这里是已经到位的完整实现

断言
objResult.Value
属于
IEnumerable
类型是失败的

存储库界面

public interface IRepository
{
    Task<IEnumerable<T>> GetListAsync<T>(string storedProcedure, object template);

    Task<IEnumerable<T>> GetListAsync<T>(string sql, CommandType commandType, object template);
}

public interface ICRUDRepository<TEntity>
{
    Task<TEntity> GetByIdAsync(long Id);

    Task<int> AddAsync(TEntity entity);

    Task<int> UpdateAsync(TEntity entity);

    Task<int> DeleteAsync(long id);
}

public interface ITARRepository : IRepository, ICRUDRepository<TARTracker>
{
    Task<IEnumerable<TARTrackerDate>> GetTARTrackerApprovedDates(long tarTrackerId);
    Task<IEnumerable<TARTrackerDate>> MergeTARApprovalDateChanges(DataTable approvedDates);
}
公共接口IRepository
{
任务GetListAsync(字符串存储过程,对象模板);
任务GetListAsync(字符串sql、CommandType、CommandType、对象模板);
}
公共接口ICRUDRepository
{
任务GetByIdAsync(长Id);
任务AddAsync(tenty实体);
任务更新同步(TEntity实体);
任务DeleteAsync(长id);
}
公共界面IRepository:IRepository、ICRUDRepository
{
任务gettartrackedprovedates(长酒石酸盐);
任务合并批准日期更改(数据表批准日期);
}
控制器

public class TARTrackerController : Controller
{
    private readonly ITARRepository Repository;
    private readonly ILogger<TARTrackerController> Logger;

    public TARTrackerController(ILogger<TARTrackerController> logger, ITARRepository repository) 
    {
        Repository = repository;
        Logger = logger;
    }

    [HttpGet("TARTrackers")]
    [SwaggerResponse(HttpStatusCode.OK, typeof(IEnumerable<ListItemDTO>))]
    [SwaggerResponse(HttpStatusCode.Unauthorized, null)]
    [SwaggerResponse(HttpStatusCode.InternalServerError, null)]
    [SwaggerResponse(HttpStatusCode.ServiceUnavailable, null)]
    [Description("Get TAR Tracker List")]
    public async Task<IActionResult> Get(long accountId)
    {
        try
        {
            var trackers = await Repository.GetListAsync<ListItemDTO>("spFDBGetAccountTARList", new { @ParamAccountID = accountId });

            return Ok(trackers);
        }
        catch (Exception e)
        {
            Logger.LogError(LogEvents.Services, e, $"An error occured in {0}.{1}", nameof(TARTrackerController), nameof(Get));

            return StatusCode((int)HttpStatusCode.InternalServerError);
        }
    }
}
公共类TARTrackerController:控制器
{
私有只读存储库;
专用只读ILogger记录器;
公共TARTrackerController(ILogger记录器,ITA存储库)
{
存储库=存储库;
记录器=记录器;
}
[HttpGet(“鞑靼人”)]
[SwaggerResponse(HttpStatusCode.OK,typeof(IEnumerable))]
[虚张声势响应(HttpStatusCode.Unauthorized,null)]
[SwaggerResponse(HttpStatusCode.InternalServerError,null)]
[虚张声势响应(HttpStatusCode.ServiceUnavailable,null)]
[说明(“获取焦油跟踪列表”)]
公共异步任务获取(长帐户ID)
{
尝试
{
var trackers=await Repository.GetListAsync(“spFDBGetAccountTARList”,new{@ParamAccountID=accountId});
返回Ok(跟踪器);
}
捕获(例外e)
{
LogError(LogEvents.Services,e,$“在{0}.{1}中发生错误”,nameof(tartrackcontroller),nameof(Get));
返回状态代码((int)HttpStatusCode.InternalServerError);
}
}
}
单元测试:

public class TARTrackerControllerTests
{
    public static ILogger<TARTrackerController> Logger = Mock.Of<ILogger<TARTrackerController>>();
    public static Mock<ITARRepository> Repository = new Mock<ITARRepository>();

    public class GetTARTrackersTests
    {
        [Fct]
        public async Task Returns_OK_With_ListItemDTO()
        {
            //arrange
            var id = 12345;
            IEnumerable<ListItemDTO> expected = new List<ListItemDTO>();

            Repository
                .Setup(repo => repo.GetListAsync<ListItemDTO>(It.IsAny<string>(), It.IsAny<object>()))
                .ReturnsAsync(expected);

            var controller = new TARTrackerController(Logger, Repository.Object);

            //act
            var result = await controller.Get(id);

            //assert
            var objResult = Assert.IsType<OkObjectResult>(result);
            Assert.Equal(typeof(IEnumerable<ListItemDTO>), objResult.Value.GetType());
        }
    }
}
公共类tartrackrcontrollertests
{
公共静态ILogger Logger=Mock.Of();
公共静态模拟存储库=新建模拟();
公共类GetArtRackerTests
{
[Fct]
公共异步任务返回带有\u ListItemDTO()的\u OK\u
{
//安排
var-id=12345;
IEnumerable预期=新列表();
存储库
.Setup(repo=>repo.GetListAsync(It.IsAny(),It.IsAny())
.ReturnsAsync(预期);
var控制器=新的TARTrackerController(记录器,Repository.Object);
//表演
var result=await controller.Get(id);
//断言
var objResult=Assert.IsType(结果);
Assert.Equal(typeof(IEnumerable),objResult.Value.GetType());
}
}
}
我觉得这应该匹配。我似乎不知道发生了什么事。有什么帮助吗?

更换

IEnumerable预期=新列表()

IEnumerable预期=可枚举。空

应该有用


然而,我不确定这在任何情况下都是一个问题;因为
IEnumerable
列表
,所以从“键入”的角度来看,它是很好的;如果类型是
List
,那么您想要对返回数据的内容进行的任何检查都会起到同样的作用,就像它是
IEnumerable

在显示为控制器代码的内容中存在拼写错误一样,这表明它不是您真正使用的代码。这可能意味着错误与测试代码无关,也可能不意味着错误与测试代码无关

我不确定代码中的问题在哪里,但这里有一个通过的测试

public class ListItemDTO { public string Name { get; set; } }

public interface IRepo
{
    Task<IEnumerable<T>> GetListAsync<T>(string storedProcedure, object template);
}

public class Ctrl
{
    private readonly IRepo repo;
    public Ctrl(IRepo repo) { this.repo = repo; }

    // BTW. Check out IAsyncEnumerable<T> 
    public async Task<IEnumerable<ListItemDTO>> GetAync()
        => await repo.GetListAsync<ListItemDTO>("spGetAccountList", new { @ParamAccountID = 1 });
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public async Task Test1()
    {
        var mockRepo = new Mock<IRepo>(MockBehavior.Strict);

        IEnumerable<ListItemDTO> expected = new List<ListItemDTO>() { new ListItemDTO { Name = "Prince" } };

        mockRepo.Setup(repo => repo.GetListAsync<ListItemDTO>(It.IsAny<string>(), It.IsAny<object>()))
                .ReturnsAsync(expected);

        var tested = new Ctrl(repo: mockRepo.Object);

        var actual = await tested.GetAync();

        Assert.IsNotNull(actual);
        Assert.AreEqual(1, actual.Count(), "Expecting exactly one item");
        var first = actual.First();
        Assert.AreEqual("Prince", first.Name, "Checking 1st item's 'Name'");
    }
}
public类ListItemDTO{public string Name{get;set;}
公共接口IRepo
{
任务GetListAsync(字符串存储过程,对象模板);
}
公共类Ctrl
{
私人只读IRepo回购协议;
公共Ctrl(IRepo repo){this.repo=repo;}
//顺便说一句,查看iSyncEnumerable
公共异步任务GetAync()
=>wait repo.GetListAsync(“spGetAccountList”,新的{@ParamAccountID=1});
}
[测试类]
公共类UnitTest1
{
[测试方法]
公共异步任务Test1()
{
var mockRepo=新模拟(MockBehavior.Strict);
IEnumerable expected=new List(){new ListItemDTO{Name=“Prince”};
mockRepo.Setup(repo=>repo.GetListAsync(It.IsAny(),It.IsAny())
.ReturnsAsync(预期);
var tested=new Ctrl(repo:mockRepo.Object);
var actual=wait tested.GetAync();
Assert.IsNotNull(实际值);
Assert.AreEqual(1,actual.Count(),“只需要一项”);
var first=实际的.first();
Assert.AreEqual(“Prince”,first.Name,“检查第一项的‘Name’”);
}
}
库设置如下所示:

<package id="Moq" version="4.13.1" targetFramework="net472" />
<package id="MSTest.TestAdapter" version="2.0.0" targetFramework="net472" />
<package id="MSTest.TestFramework" version="2.0.0" targetFramework="net472" />

因此,似乎只有断言是错误的,这是这里的普遍共识,但实际上应该通过以下方式来实现

Assert.IsAssignableFrom<IEnumerable<ListItemDTO>>(objResult.Value);
Assert.IsAssignableFrom(objResult.Value);

您是否尝试过
expected.AsEnumerable()
?@MuhammadHannan是的,它仍然返回
列表
@dbarth实际发生的事情与您预期发生的事情相对应。我怀疑您预期的是
expected.GetType())
返回
IEnumerable
-请您发帖澄清是这样还是现在(以及更新样本代码+@Nkosi建议的预期结果),您真的关心实际值的类型吗?您关心的是返回的值可以被枚举并包含期望的值。@tymtam-因为它返回一个
IEnumerable
,这将是一个精确的类型匹配。请记住,最初提出的问题并没有真正弄清楚问题是什么(没有细节)