简体   繁体   English

使用moq设置方法以返回对象列表但获取null

[英]Using moq to setup a method to return a list of objects but getting null

I've been testing around in my personal projects and ran to this little problem. 我一直在我的个人项目中进行测试,并遇到了这个小问题。 I have a test method that creates a list of objects, I setup a service I use in my method I test to return the mock list. 我有一个创建对象列表的测试方法,设置了我在测试方法中使用的服务以返回模拟列表。 How ever, for some reason the setup is not working and it is returning null. 但是,由于某种原因,安装程序无法正常工作,并且返回null。

Here is the test method: 这是测试方法:

var mockList = new List<IBillItem>
{
    new BillItem
    {
        Id = 0,
        DueDate = new DateTime(),
        Name = "",
        IndexNumber = "",
        AccountNumber = "",
        Amount = decimal.One
    },
    new BillItem
    {
        Id = 0,
        DueDate = new DateTime(),
        Name = "",
        IndexNumber = "",
        AccountNumber = "",
        Amount = decimal.One
    }
};

_billHandlingService.Setup(x => x.GetAllBillsAsync(It.IsAny<string>())).Returns(Task.FromResult(mockList));

var listBillsVm = new ListBillsViewModel(new LoggerFactory(), _billHandlingService.Object, _settingsService.Object);

await listBillsVm.GetBillsAsync();

_billHandlingService.Verify(x => x.GetAllBillsAsync(_settingsService.Name), Times.AtMostOnce);

Assert.AreEqual(1, listBillsVm.BillsList.Count);

And here is the code of the concrete class im testing: 这是即时测试的具体类的代码:

public async Task GetBillsAsync()
{
    BillsList.Clear();

    var bills = await _billHandlingService.GetAllBillsAsync(_settingsService.LoggerUser);

    if (null != bills)
    {
        var billsByDate = bills.Where(x => x.DueDate == DateTime.Today).ToList();
        foreach (var bill in billsByDate)
        {
            BillsList.Add(bill);
            RaisePropertyChanged(nameof(BillsList));
        }
    }
}

I Have tried searching SO / google for results an yet to find any answer. 我曾尝试在SO / google中搜索结果,但尚未找到任何答案。 Thanks in advance. 提前致谢。

Edit: The code is not commented but I believe its clear enough, ask in comments if there's something that needs clearing 编辑:该代码未注释,但我相信它足够清晰,请在注释中询问是否需要清除某些内容

Edit 2: 编辑2:

Task<List<IBillItem>>GetAllBillsAsync(string username); 

Is the interface for the method being called. 是被调用方法的接口。

You could Try changing the .Returns in the Setup to .ReturnsAsync(mockList) 你可以试着改变.ReturnsSetup.ReturnsAsync(mockList)

//...other code removed for brevity
_billHandlingService
    .Setup(x => x.GetAllBillsAsync(It.IsAny<string>()))
    .ReturnsAsync(mockList);
//...other code removed for brevity

UPDATE UPDATE

The Following minimal complete verifiable example was used based on your question to try and reproduce your issue. 根据您的问题,使用了以下最低限度的完整可验证示例,以尝试重现您的问题。 Note that I omitted any classes that were not necessary to create the test. 请注意,我省略了创建测试不必要的任何类。

class ListBillsViewModel {
    private IBillHandlingService _billHandlingService;
    private ISettingsService _settingsService;

    public ListBillsViewModel(IBillHandlingService billHandlingService, ISettingsService settingsService) {
        this._billHandlingService = billHandlingService;
        this._settingsService = settingsService;
        BillsList = new List<IBillItem>();
    }

    public List<IBillItem> BillsList { get; set; }

    public async Task GetBillsAsync() {
        BillsList.Clear();

        var bills = await _billHandlingService.GetAllBillsAsync(_settingsService.LoggerUserName);

        if (null != bills) {
            var billsByDate = bills.Where(x => x.DueDate == DateTime.Today).ToList();
            foreach (var bill in billsByDate) {
                BillsList.Add(bill);
            }
        }
    }
}

public interface ISettingsService {
    string Name { get; }
    string LoggerUserName { get; set; }
}

public interface IBillHandlingService {
    Task<List<IBillItem>> GetAllBillsAsync(string username);
}

public class BillItem : IBillItem {
    public int Id { get; set; }
    public DateTime DueDate { get; set; }
    public string Name { get; set; }
    public string IndexNumber { get; set; }
    public string AccountNumber { get; set; }
    public decimal Amount { get; set; }
}

public interface IBillItem {
    int Id { get; set; }
    DateTime DueDate { get; set; }
    string Name { get; set; }
    string IndexNumber { get; set; }
    string AccountNumber { get; set; }
    decimal Amount { get; set; }
}

The following Unit test was then reconstructed based on the above classes 然后根据上述类别重建以下单元测试

[TestMethod]
public async Task Moq_Setup_Should_Return_List_Of_Objects() {
    var mockList = new List<IBillItem>
    {
        new BillItem
        {
            Id = 0,
            DueDate = DateTime.Today,
            Name = "User",
            IndexNumber = "",
            AccountNumber = "",
            Amount = decimal.One
        },
        new BillItem
        {
            Id = 1,
            DueDate = DateTime.Today.AddDays(1),
            Name = "User",
            IndexNumber = "",
            AccountNumber = "",
            Amount = decimal.One
        }
    };

    string name = "User";

    var _settingsService = new Mock<ISettingsService>();
    _settingsService
        .Setup(m => m.Name)
        .Returns(name);
    _settingsService
        .Setup(m => m.LoggerUserName)
        .Returns(name);

    var _billHandlingService = new Mock<IBillHandlingService>();
    _billHandlingService
        .Setup(x => x.GetAllBillsAsync(It.IsAny<string>()))
        .ReturnsAsync(mockList);

    var listBillsVm = new ListBillsViewModel(_billHandlingService.Object, _settingsService.Object);

    await listBillsVm.GetBillsAsync();

    _billHandlingService.Verify(x => x.GetAllBillsAsync(_settingsService.Name), Times.AtMostOnce);

    Assert.AreEqual(1, listBillsVm.BillsList.Count);
}

I ran the above test and it passes as expected for both setups with .Returns(Task.FromResult(mockist)) and .ReturnsAsync(mockList) . 我运行了上述测试,并且通过.Returns(Task.FromResult(mockist)).ReturnsAsync(mockList)两个设置.Returns(Task.FromResult(mockist))预期通过了测试。

Either the example you gave does not match your actual situation or the problem is outside of what you are describing in your post. 您提供的示例与您的实际情况不符,或者问题超出了您在帖子中所描述的范围。

You need to specify the List<IBillItem> on the Task.FromResult , like this: 你需要指定List<IBillItem>Task.FromResult ,就像这样:

_billHandlingService.Setup<Task<List<IBillItem>>>(
    x => x.GetAllBillsAsync(It.IsAny<string>()))
                    .Returns(Task.FromResult<List<IBillItem>>(mockList));

Similar SO Q and A here . 这里的 SO Q和A相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM