【问题标题】:NUnit Test method with Rhino mocks does not work - C#带有 Rhino 模拟的 NUnit 测试方法不起作用 - C#
【发布时间】:2018-11-09 07:42:43
【问题描述】:

我已经创建了一个 web api 项目,并分别在 AccountController 中实现了以下 HTTP POST 方法以及在 AccountService 和 AccountRepository 中的相关服务方法和存储库方法。

// WEB API 
public class AccountController : ApiController
{
    private readonly IAccountService _accountService;
    public AccountController()
    {
        _accountService = new AccountService();
    }

    [HttpPost, ActionName("updateProfile")]
    public IHttpActionResult updateProfile([FromBody]RequestDataModel request)
    {
        var response = _accountService.UpdateProfile(request.UserId, request.Salary);
        return Json(response);
    }
}


public class RequestDataModel
{
    public int UserId { get; set; }
    public decimal Salary { get; set; }
}

// Service / Business Layer

public interface IAccountService
{
    int UpdateProfile(int userId, decimal salary);
}

public class AccountService : IAccountService
{
    readonly IAccountRepository _accountRepository = new AccountRepository();

    public int UpdateProfile(int userId, decimal salary)
    {
        return _accountRepository.UpdateProfile(userId, salary);
    }
}


// Repository / Data Access Layer

public interface IAccountRepository
{
    int UpdateProfile(int userId, decimal salary);
}

public class AccountRepository : IAccountRepository
{
    public int UpdateProfile(int userId, decimal salary)
    {
        using (var db = new AccountEntities())
        {
            var account = (from b in db.UserAccounts where b.UserID == userId select b).FirstOrDefault();
            if (account != null)
            {
                account.Salary = account.Salary + salary;
                db.SaveChanges();
                return account.Salary;
            }
        }
        return 0;
    }
}

另外,我想实现一个 NUNIT 测试用例。这是代码。

public class TestMethods
{
    private IAccountService _accountService;
    private MockRepository _mockRepository;

    [SetUp]
    public void initialize()
    {
        _mockRepository = new MockRepository();

    }

    [Test]
    public void TestMyMethod()
    {
        var service = _mockRepository.DynamicMock<IAccountService>();

        using (_mockRepository.Playback())
        {
            var updatedSalary = service.UpdateProfile(123, 1000);
            Assert.AreEqual(1000, updatedSalary);
        } 
    }
}

请注意,我使用 Rhino 模拟库来实现模拟存储库。

问题是这不会返回预期的输出。看起来它不会触发我的服务类中的 UpdateProfile() 方法。它返回 NULL。

【问题讨论】:

  • 您似乎期望模拟具有某种行为,而您没有通过设置实际注入该行为。
  • 我想以 1000 的薪水为 userId 123 运行测试,我应该得到测试结果为 1000。但它不应该更新数据库
  • 那么需要重构该api控制器以遵循显式依赖原则。然后可以将服务的模拟直接注入到被测类中。
  • 你到底想测试什么?

标签: c# asp.net asp.net-web-api nunit rhino-mocks


【解决方案1】:

所有这些类都与实现问题紧密耦合,应重构为解耦并依赖于抽象。

public class AccountController : ApiController  {
    private readonly IAccountService accountService;

    public AccountController(IAccountService accountService) {
        this.accountService = accountService;
    }

    [HttpPost, ActionName("updateProfile")]
    public IHttpActionResult updateProfile([FromBody]RequestDataModel request) {
        var response = accountService.UpdateProfile(request.UserId, request.Salary);
        return Ok(response);
    }
}

public class AccountService : IAccountService {
    private readonly IAccountRepository accountRepository;

    public AccountService(IAccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    public int UpdateProfile(int userId, decimal salary) {
        return accountRepository.UpdateProfile(userId, salary);
    }
}

现在对于孤立的单元测试,可以模拟抽象依赖项并将其注入到被测对象中。

例如,以下通过模拟IAccountRepository 并将其注入AccountService 来测试AccountService.UpdateProfile

public class AccountServiceTests {

    [Test]
    public void UpdateProfile_Should_Return_Salary() {
        //Arrange
        var accountRepository = MockRepository.GenerateMock<IAccountRepository>(); 
        var service = new AccountService(accountRepository);

        var userId = 123;
        decimal salary = 1000M;
        var expected = 1000;

        accountRepository.Expect(_ => _.UpdateProfile(userId, salary)).Return(expected);

        //Act
        var updatedSalary = service.UpdateProfile(userId, salary);

        //Assert
        Assert.AreEqual(expected, updatedSalary);
    }
}

同样的方法可以用来测试AccountController。相反,您将模拟 IAccountService 并将其注入控制器以测试操作并断言预期的行为。

确保将抽象及其实现注册到应用程序组合根中的 DI 容器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多