Azure函数Xunit模拟测试中的错误:恰好在模拟上的预期调用1次,但为0次

发布于 2025-02-06 17:47:23 字数 2991 浏览 2 评论 0原文

我在下面的时间触发代码中创建了一个Azure函数。我是Azure功能和Xunit的新手。我在一些博客的帮助下创建了这两个。我在C#中使用Xunit编写了一个简单的单元测试。但是它返回错误。我试图解决这个问题而不对我有用。.请帮助我

public class DeleteJob
{
    private readonly IStore _store;

    public DeleteJob(IStore store, ILogger<DeleteJob> log)
    {
        _store = store;
        _log = log;
    }

    [Function("DeleteJob")]
    public async Task Run([TimerTrigger("0 */5 * * * *", RunOnStartup = false)] MyInfo myTimer)
    {
        
        var canceltoken = new CancellationTokenSource(TimeSpan.FromMinutes(8));
        var deleteDate = DateTime.UtcNow.AddMonths(-6);
        try
        {
            await DeleteBlobMetadata(deleteDate, canceltoken.Token);
        }
        catch (OperationCanceledException)
        {
            _log.LogInformation("Function ran out of time");
        }
       
    }

    private async Task DeleteBlobMetadata(DateTime deleteDate, CancellationToken canceltoken)
    {
        try
        {
            if (cancellationToken.IsCancellationRequested)
                return;
            var BlobUrls = await _store.GetBlobBeforeDate(Constants.ContainerName, deleteDate);
            foreach (var blobName in BlobUrls)
            {
                if (cancellationToken.IsCancellationRequested)
                    return;
                await _store.DeleteBlobAsync(Constants.ContainerName, blobName);
            }
        }
        catch (Exception e) 
        {
            _log.LogError($"Exception when deleting attachments: \n{e}");
        }

以下是Unitest

public class DeleteTest
{

    private readonly Mock<IStore> _StoreMock;
    private Mock<ILogger<DeleteJob>> _logMock;

    public DeleteTest()
    {
        _StoreMock = new Mock<IStore>();
        _logMock = new Mock<ILogger<DeleteJob>>();
    }
    [Fact]
    public async Task DeleteBlobOlderThan6Months_ShouldDelete()
    {
        SetupDeletionSuccessful(true);
        SetupDeleteBlobSetup();
        var sut = GetSut();
        await sut.Run(myTimer: null);
        _StoreMock.Verify(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()), Times.Exactly(1));
        _StoreMock.Verify(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(1));

    }
    private void SetupDeleteBlobSetup()
    {
        _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
                .ReturnsAsync(new List<string> { "someUrl" });

    }

  private void SetupDeletionSuccessful(bool successfulDeletion)
    {
        _StoreMock.Setup(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(successfulDeletion);
    }

错误是

 Expected invocation on the mock exactly 1 times, but was 0 times:
 m => m.GetBlobBeforeDate(It.IsAny<string>(), It.IsAny<DateTime>())

I created a azure function with the time trigger code below. Im very new to azure function and xunit. I created both with help of some blogs. I wrote a simple unit test using Xunit in C#. but it returns an error. I tried to solve the issue and not work for me.. Please help me

public class DeleteJob
{
    private readonly IStore _store;

    public DeleteJob(IStore store, ILogger<DeleteJob> log)
    {
        _store = store;
        _log = log;
    }

    [Function("DeleteJob")]
    public async Task Run([TimerTrigger("0 */5 * * * *", RunOnStartup = false)] MyInfo myTimer)
    {
        
        var canceltoken = new CancellationTokenSource(TimeSpan.FromMinutes(8));
        var deleteDate = DateTime.UtcNow.AddMonths(-6);
        try
        {
            await DeleteBlobMetadata(deleteDate, canceltoken.Token);
        }
        catch (OperationCanceledException)
        {
            _log.LogInformation("Function ran out of time");
        }
       
    }

    private async Task DeleteBlobMetadata(DateTime deleteDate, CancellationToken canceltoken)
    {
        try
        {
            if (cancellationToken.IsCancellationRequested)
                return;
            var BlobUrls = await _store.GetBlobBeforeDate(Constants.ContainerName, deleteDate);
            foreach (var blobName in BlobUrls)
            {
                if (cancellationToken.IsCancellationRequested)
                    return;
                await _store.DeleteBlobAsync(Constants.ContainerName, blobName);
            }
        }
        catch (Exception e) 
        {
            _log.LogError(
quot;Exception when deleting attachments: \n{e}");
        }

Following is unittest

public class DeleteTest
{

    private readonly Mock<IStore> _StoreMock;
    private Mock<ILogger<DeleteJob>> _logMock;

    public DeleteTest()
    {
        _StoreMock = new Mock<IStore>();
        _logMock = new Mock<ILogger<DeleteJob>>();
    }
    [Fact]
    public async Task DeleteBlobOlderThan6Months_ShouldDelete()
    {
        SetupDeletionSuccessful(true);
        SetupDeleteBlobSetup();
        var sut = GetSut();
        await sut.Run(myTimer: null);
        _StoreMock.Verify(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()), Times.Exactly(1));
        _StoreMock.Verify(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(1));

    }
    private void SetupDeleteBlobSetup()
    {
        _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
                .ReturnsAsync(new List<string> { "someUrl" });

    }

  private void SetupDeletionSuccessful(bool successfulDeletion)
    {
        _StoreMock.Setup(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(successfulDeletion);
    }

Error is

 Expected invocation on the mock exactly 1 times, but was 0 times:
 m => m.GetBlobBeforeDate(It.IsAny<string>(), It.IsAny<DateTime>())

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我为君王 2025-02-13 17:47:24

错误消息是完全正确的。在您的测试中,getBlobBeforedate()未被调用:

在您的测试设置中getBlobbeforedate返回空列表的方法:

 _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
        .ReturnsAsync(new List<string>());

这意味着在您的功能中,没有blob url url删除。 Because in your function you delete all blobUrls that have been returned by GetBlobBeforeDate. No items =>没什么可删除的。

如果您希望测试验证deletTachmentAsync一旦您需要新设置,就可以准确调用。例如:

 _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
        .ReturnsAsync(new List<string> { "someUrl" });

编辑:

在更多内容上,这一次在您的代码中您致电:

await _store.DeleteBlobAsync(Constants.AttachmentContainerName, blobName);

但是相应的模拟设置是:

_StoreMock.Setup(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(successfulDeletion);

您可以看到,您将苹果与橙色进行比较。错误仍然正确:deletTachmentsAsync从未被调用。

同样,在您的代码中,您也使用常数。

我建议将您的模拟设置更加明确一些,并包括相应的容器名称。例如:

_StoreMock.Setup(m => m.GetBlobBeforeDate(Constants.ContainerName, It.IsAny<DateTime>()))
                .ReturnsAsync(new List<string> { "someUrl" });

这样,模拟还将验证该方法已与预期containerame参数值调用。

The error message is perfectly right. In your test the GetBlobBeforeDate() does not get called:

In your test setup the GetBlobBeforeDate method to return an empty list:

 _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
        .ReturnsAsync(new List<string>());

This means in you function there will be no blob url to delete. Because in your function you delete all blobUrls that have been returned by GetBlobBeforeDate. No items => nothing to delete.

If you want your test to verify that DeleteAttachmentAsync gets called exactly once you need a new setup. For example:

 _StoreMock.Setup(m => m.GetBlobBeforeDate(It.IsAny<string>(),It.IsAny<DateTime>()))
        .ReturnsAsync(new List<string> { "someUrl" });

Edit:

On more thing, this time in your code you call:

await _store.DeleteBlobAsync(Constants.AttachmentContainerName, blobName);

But what should be the corresponding Mock setup is:

_StoreMock.Setup(m => m.DeleteAttachmentAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(successfulDeletion);

As you can see you are comparing apples to oranges. The error is still right: DeleteAttachmentsAsync never gets called.

Also in your code you use both Constants.ContainerName nad Constants.AttachmentContainerName which also seems wrong.

I suggest to setup your Mocks a little bit more explicit and include the corresponding container name. For example:

_StoreMock.Setup(m => m.GetBlobBeforeDate(Constants.ContainerName, It.IsAny<DateTime>()))
                .ReturnsAsync(new List<string> { "someUrl" });

This way the mock will also verify that the method has been called with the expected containerName parameter value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文