使用 Moq 进行单元测试 api CRUD 操作

时间:2021-02-21 14:23:16

标签: c# asp.net unit-testing asp.net-core asp.net-web-api

我对单元测试完全陌生,我尝试为 crud 操作编写单元测试。我可以为 get by idget all 编写单元测试。但是在为createupdate 编写单元测试时出现了问题。

这是我创建方法的控制器代码

public async Task<IActionResult> Create([FromBody] Message message)
    {
        var duplicatemessage = await _messageService.DuplicateMessage(message.Text);
        if (duplicatemessage == null)
        {
            _messageService.Create(message);
            return CreatedAtRoute("Api", new { id = message.Id.ToString() }, message);
        }
        else
        {
            return BadRequest(new { message = "Text Already Exist" });
        }
    }

这是我为create方法写的单元测试

[TestCase("Hello")]
    public async Task Create_StateUnderTest_ExpectedBehavior(Message message)
    {
        // Arrange
        // mockMessageService.Setup(t => t.GetId(id)).ReturnsAsync(new Message());
        mockMessageService.Setup(t => t.DuplicateMessage(message.Text)).ReturnsAsync(new Message());
        mockMessageService.Setup(t => t.Create(message)).Returns(new Message());
        var apiController = this.CreateApiController();
        //var message1 = new Message() { Text = "Hello" };

        // Act
        var result = await apiController.Create(message);

        // Assert
        Assert.IsInstanceOf<CreatedAtRouteResult>(result);
        this.mockRepository.VerifyAll();
    }

当我运行测试时出现此错误

留言: System.ArgumentException:“System.String”类型的对象无法转换为“HelloApi.Models.Message”类型。

堆栈跟踪: RuntimeType.TryChangeType(对象值,Binder 绑定器,CultureInfo 文化,布尔需要SpecialCast) RuntimeType.CheckValue(对象值,Binder 绑定器,CultureInfo 文化,BindingFlags invokeAttr) MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfoculture, Signature sig) RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) MethodBase.Invoke(Object obj, Object[] 参数) Reflect.InvokeMethod(MethodInfo method, Object fixture, Object[] args)

我尝试调试但未命中调试点。 我试过, Test api CRUD operation with MoqHow can I convert an Class Object into String? 这但我认为这与我的问题无关。有谁能帮帮我吗?

3 个答案:

答案 0 :(得分:1)

您正在尝试在您的 Api 控制器上测试方法“create”。 所以让我们来看看你的 Api 控制器的依赖关系。 它取决于_messageService,特别是这两个方法-

  1. 重复消息
  2. 创建

现在在您的测试用例中,我看到您已经设置了 messageservice 'GetId' 方法的最小起订量,但没有设置上述两个依赖方法。 所以首先你需要设置 'DuplicateMessage' 方法来返回你期望它返回的类型。您可以进行 2 次测试,一个是在它返回 null 时测试 if 块,另一个是在它返回预期值(即不为 null 以测试 else 块)时。

对于如果块测试,您需要为 messageService 上的“创建”方法进行模拟设置。 然后让它返回预期的类型来验证它。

答案 1 :(得分:1)

您需要在构造函数初始化中注入您的模拟服务。像这样的东西。

var apiController = this.CreateApiController(mockMessageService);

答案 2 :(得分:0)

我可以通过这种方式解决问题。

此测试用于创建新消息

这里我采用了两个参数 id 和 Text,并通过使用将其与我的模型类变量 Id 和 Text 相等,

var message = new Message() { Text = Text, Id = id };

[TestCase("Hello", "5fda6c5c49f10b1464f1f2ce")]
    public async Task Create_StateUnderTest_ExpectedBehavior(string Text, string id)
    {

        // Arrange
        var message = new Message() { Text = Text, Id = id };
        mockMessageService.Setup(t => t.GetId(id)).ReturnsAsync(new Message());
        mockMessageService.Setup(t => t.DuplicateMessage(message.Text)).ReturnsAsync(new Message());
        mockMessageService.Setup(t => t.Create(message)).Returns(new Message());
        var apiController = this.CreateApiController();
        var message1 = new Message() { Text = "Hellooo", Id = "5fda6c5c49f10b1464f1f2ca" };

        // Act
        var result = await apiController.Create(message1);

        // Assert
        Assert.IsInstanceOf<CreatedAtRouteResult>(result);
        this.mockRepository.Verify();
    }

所以这里从 testcase 和 message1 传递的值不相等,它不是重复的消息,所以它应该创建一个。因此测试用例是成功的。

此测试用于重复检查

[TestCase("Hello", "5fda6c5c49f10b1464f1f2ce")]
    public async Task Create_StateUnderTest_UnExpectedBehavior(string Text, string id)
    {

        // Arrange
        var message = new Message() { Text = Text, Id = id };
        mockMessageService.Setup(t => t.GetId(id)).ReturnsAsync(new Message());
        mockMessageService.Setup(t => t.Create(message)).Returns(new Message());
        mockMessageService.Setup(t => t.DuplicateMessage(message.Text)).ReturnsAsync(new Message());
        var apiController = this.CreateApiController();
        var message1 = new Message() { Text = "Hello", Id = "5fda6c5c49f10b1464f1f2ce" };

        // Act
        var result = await apiController.Create(message1);

        // Assert
        Assert.IsInstanceOf<BadRequestObjectResult>(result);
        this.mockRepository.Verify();
    }

之前的问题是我传递对象的方式。现在这对我来说很好用。如果我错了,你可以纠正我:) 谢谢大家的帮助!

相关问题