使用 Rhino 模拟的 NUnit 测试方法不起作用 - C#
NUnit Test method with Rhino mocks does not work - C#
我创建了一个 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 模拟库来实现模拟存储库。
问题是这不是 return 预期的输出。看起来它不会触发我的服务 class 中的 UpdateProfile() 方法。它 return 为 NULL。
所有这些 类 都与实现问题紧密耦合,应该重构以解耦并依赖于抽象。
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 容器注册抽象及其实现。
我创建了一个 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 模拟库来实现模拟存储库。
问题是这不是 return 预期的输出。看起来它不会触发我的服务 class 中的 UpdateProfile() 方法。它 return 为 NULL。
所有这些 类 都与实现问题紧密耦合,应该重构以解耦并依赖于抽象。
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 容器注册抽象及其实现。