You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用xUnit与Moq编写ProductController的Delete动作单元测试?

ProductController Delete动作的单元测试方案(xUnit + Moq)

一、GET /Product/Delete/{id} 的测试场景与代码

该动作负责返回删除确认页面,需验证以下场景:

  • 传入存在的产品ID时,返回包含对应Product对象的View
  • 传入不存在的产品ID时,返回包含null的View

测试代码示例:

using Xunit;
using Moq;
using YourNamespace.Controllers;
using YourNamespace.Services;
using YourNamespace.Models;

public class ProductControllerTests
{
    private readonly Mock<IProductService> _mockProductService;
    private readonly ProductController _controller;

    public ProductControllerTests()
    {
        _mockProductService = new Mock<IProductService>();
        _controller = new ProductController(_mockProductService.Object);
    }

    [Fact]
    public void Delete_Get_ReturnsViewWithProduct_WhenIdExists()
    {
        // 准备测试数据
        var testProduct = new Product { Id = 1, Name = "Test Product" };
        _mockProductService.Setup(s => s.GetById(1)).Returns(testProduct);

        // 执行动作
        var result = _controller.Delete(1);

        // 断言结果
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Equal(testProduct, viewResult.Model);
        _mockProductService.Verify(s => s.GetById(1), Times.Once);
    }

    [Fact]
    public void Delete_Get_ReturnsViewWithNull_WhenIdDoesNotExist()
    {
        // 准备:模拟不存在ID的返回值
        _mockProductService.Setup(s => s.GetById(999)).Returns((Product)null);

        // 执行动作
        var result = _controller.Delete(999);

        // 断言结果
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Null(viewResult.Model);
        _mockProductService.Verify(s => s.GetById(999), Times.Once);
    }
}

二、POST /Product/Delete/{id} 的测试场景与代码

该动作负责执行实际删除逻辑,需验证以下场景:

  • 删除成功时,重定向到Index页面
  • 删除抛出异常时,返回错误View

测试代码示例:

[Fact]
public void Delete_Post_RedirectsToIndex_WhenDeleteSucceeds()
{
    // 准备:模拟删除成功的行为
    _mockProductService.Setup(s => s.Remove(1)).Verifiable();

    // 执行动作
    var result = _controller.Delete(1, null);

    // 断言结果
    var redirectResult = Assert.IsType<RedirectToActionResult>(result);
    Assert.Equal(nameof(ProductController.Index), redirectResult.ActionName);
    _mockProductService.Verify(s => s.Remove(1), Times.Once);
}

[Fact]
public void Delete_Post_ReturnsView_WhenDeleteThrowsException()
{
    // 准备:模拟删除抛出异常
    _mockProductService.Setup(s => s.Remove(1)).Throws(new Exception("Delete failed"));

    // 执行动作
    var result = _controller.Delete(1, null);

    // 断言结果
    Assert.IsType<ViewResult>(result);
    _mockProductService.Verify(s => s.Remove(1), Times.Once);
}

额外:ProductService.Remove方法的集成测试

如果需要验证服务层的删除逻辑(直接操作DbContext),可使用EF Core内存数据库编写集成测试:

using Xunit;
using Microsoft.EntityFrameworkCore;
using YourNamespace.Services;
using YourNamespace.Models;

public class ProductServiceTests
{
    [Fact]
    public void Remove_DeletesProduct_FromDatabase()
    {
        // 准备内存数据库
        var options = new DbContextOptionsBuilder<DataBaseContext>()
            .UseInMemoryDatabase(databaseName: "Test_Delete_Product")
            .Options;

        // 初始化测试数据
        using (var context = new DataBaseContext(options))
        {
            context.Products.Add(new Product { Id = 1, Name = "Test Product" });
            context.SaveChanges();
        }

        // 执行删除并验证
        using (var context = new DataBaseContext(options))
        {
            var service = new ProductService(context);
            service.Remove(1);

            var deletedProduct = context.Products.Find(1);
            Assert.Null(deletedProduct);
        }
    }

    [Fact]
    public void Remove_ThrowsException_WhenProductNotFound()
    {
        // 准备空的内存数据库
        var options = new DbContextOptionsBuilder<DataBaseContext>()
            .UseInMemoryDatabase(databaseName: "Test_Delete_NonExistent_Product")
            .Options;

        using (var context = new DataBaseContext(options))
        {
            var service = new ProductService(context);
            // 断言删除不存在的产品会抛出异常
            Assert.Throws<InvalidOperationException>(() => service.Remove(999));
        }
    }
}

内容的提问来源于stack exchange,提问作者Najmeh Sh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:31:21