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

如何对void返回类型的Create方法做单元测试?是否需修改返回类型?

Hey there! Great question—void methods absolutely can be unit tested effectively without changing their return type. Let’s break down how to approach this, along with whether adjusting the return type makes sense.

1. What to Test for Your Create Method

Your Create method has clear responsibilities, so we can test around those behaviors instead of relying on a return value:

  • Exception scenarios: Verify that the correct CusException is thrown when invalid inputs are provided (null car, existing login, existing email).
  • Dependency interactions: Ensure that the right methods on your dependencies (ICarQuery and ICarRepository) are called at the right times, with the right arguments.
  • Validation flow: Confirm that all pre-checks (login/email existence) are executed when a valid car is provided.

2. Is Changing Return Type to bool Reasonable?

Short answer: Probably not necessary, just for testing.

Your current design uses exceptions to signal errors, which is a valid approach—exceptions carry detailed error context (like your Error enum and message) and force callers to handle failure cases explicitly. Changing to a bool would lose that context, and require callers to guess why the operation failed.

If your business logic specifically needs to return a success/failure status (with details), that’s a different conversation—but purely for testing, modifying the method’s signature is an unnecessary workaround.

3. Practical Unit Test Examples (Using Moq)

Let’s use Moq (a popular .NET mocking framework) to write tests covering all key scenarios.

Test 1: Null Car Throws Exception

[Test]
public void Create_WithNullCar_ThrowsCusException()
{
    // Arrange
    var mockCarQuery = new Mock<ICarQuery>();
    var mockCarRepo = new Mock<ICarRepository>();
    var service = new CreateCarService(mockCarQuery.Object, mockCarRepo.Object);

    // Act & Assert
    Assert.Throws<CusException>(() => service.Create(null));
}

Test 2: Existing Login Throws Exception

[Test]
public void Create_WithExistingLogin_ThrowsCusException()
{
    // Arrange
    var testCar = new Car { Login = "already-taken", Email = "test@example.com" };
    var mockCarQuery = new Mock<ICarQuery>();
    mockCarQuery.Setup(q => q.IsLoginExist(testCar.Login)).Returns(true);
    var mockCarRepo = new Mock<ICarRepository>();
    var service = new CreateCarService(mockCarQuery.Object, mockCarRepo.Object);

    // Act & Assert
    var exception = Assert.Throws<CusException>(() => service.Create(testCar));
    Assert.AreEqual("Message1", exception.Message);
    // You can also verify the Error enum value here if needed
}

Test 3: Valid Car Triggers Repository Add

[Test]
public void Create_WithValidCar_CallsRepositoryAddOnce()
{
    // Arrange
    var testCar = new Car { Login = "new-user", Email = "new@example.com" };
    var mockCarQuery = new Mock<ICarQuery>();
    mockCarQuery.Setup(q => q.IsLoginExist(testCar.Login)).Returns(false);
    mockCarQuery.Setup(q => q.IsEmailExist(testCar.Email)).Returns(false);
    var mockCarRepo = new Mock<ICarRepository>();
    var service = new CreateCarService(mockCarQuery.Object, mockCarRepo.Object);

    // Act
    service.Create(testCar);

    // Assert
    mockCarRepo.Verify(repo => repo.Add(testCar), Times.Once);
}

Test 4: Valid Car Runs Both Existence Checks

[Test]
public void Create_WithValidCar_ExecutesBothExistenceChecks()
{
    // Arrange
    var testCar = new Car { Login = "new-user", Email = "new@example.com" };
    var mockCarQuery = new Mock<ICarQuery>();
    mockCarQuery.Setup(q => q.IsLoginExist(testCar.Login)).Returns(false);
    mockCarQuery.Setup(q => q.IsEmailExist(testCar.Email)).Returns(false);
    var mockCarRepo = new Mock<ICarRepository>();
    var service = new CreateCarService(mockCarQuery.Object, mockCarRepo.Object);

    // Act
    service.Create(testCar);

    // Assert
    mockCarQuery.Verify(q => q.IsLoginExist(testCar.Login), Times.Once);
    mockCarQuery.Verify(q => q.IsEmailExist(testCar.Email), Times.Once);
}

Wrapping Up

By focusing on behavior (exceptions thrown, dependencies called) instead of return values, you can fully test your void method without altering its original design. This keeps your code clean and your tests focused on what the method is actually supposed to do.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 07:32:48