关键词:
Controller:
public class ApplyController : Controller
private readonly ICreditCardApplicationRepository _applicationRepository;
public ApplyController(ICreditCardApplicationRepository applicationRepository)
_applicationRepository = applicationRepository;
public IActionResult Index()
return View();
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(NewCreditCardApplicationDetails applicationDetails)
if (!ModelState.IsValid)
return View(applicationDetails);
var creditCardApplication = new CreditCardApplication
FirstName = applicationDetails.FirstName,
LastName = applicationDetails.LastName,
FrequentFlyerNumber = applicationDetails.FrequentFlyerNumber,
Age = applicationDetails.Age.Value,
GrossAnnualIncome = applicationDetails.GrossAnnualIncome.Value
;
await _applicationRepository.AddAsync(creditCardApplication);
return View("ApplicationComplete", creditCardApplication);
public IActionResult Error()
return View();
Interface:
public interface ICreditCardApplicationRepository
Task AddAsync(CreditCardApplication application);
Implementation:
public class EntityFrameworkCreditCardApplicationRepository : ICreditCardApplicationRepository
private readonly AppDbContext _dbContext;
public EntityFrameworkCreditCardApplicationRepository(AppDbContext dbContext)
_dbContext = dbContext;
public Task AddAsync(CreditCardApplication application)
_dbContext.CreditCardApplications.Add(application);
return _dbContext.SaveChangesAsync();
NewCreditCardApplicationDetails model:
public class NewCreditCardApplicationDetails
[Display(Name = "First Name")]
[Required(ErrorMessage = "Please provide a first name")]
public string FirstName get; set;
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Please provide a last name")]
public string LastName get; set;
[Display(Name = "Age (in years)")]
[Required(ErrorMessage = "Please provide an age in years")]
[Range(18,int.MaxValue, ErrorMessage = "You must be at least 18 years old")]
public int? Age get; set;
[Display(Name = "Gross Income")]
[Required(ErrorMessage = "Please provide your gross income")]
public decimal? GrossAnnualIncome get; set;
public string FrequentFlyerNumber get; set;
unit test:
public class ApplyControllerShould
private readonly Mock<ICreditCardApplicationRepository> _mockRepository;
private readonly ApplyController _sut;
public ApplyControllerShould()
_mockRepository = new Mock<ICreditCardApplicationRepository>();
_sut = new ApplyController(_mockRepository.Object);
[Fact]
public void ReturnViewForIndex()
IActionResult result = _sut.Index();
Assert.IsType<ViewResult>(result);
[Fact]
public async Task ReturnViewWhenInvalidModelState()
_sut.ModelState.AddModelError("x", "Test Error");
var application = new NewCreditCardApplicationDetails()
FirstName = "Sarah"
;
IActionResult result = await _sut.Index(application);
ViewResult viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsType<NewCreditCardApplicationDetails>(viewResult.Model);
Assert.Equal(application.FirstName, model.FirstName);
[Fact]
public async Task NotSaveApplicationWhenModelError()
_sut.ModelState.AddModelError("x", "Test Error");
var application = new NewCreditCardApplicationDetails();
await _sut.Index(application);
_mockRepository.Verify(
x => x.AddAsync(It.IsAny<CreditCardApplication>()), Times.Never);
[Fact]
public async Task SaveApplicationWhenValidModel()
CreditCardApplication saveApplication = null;
_mockRepository.Setup(x => x.AddAsync(It.IsAny<CreditCardApplication>()))
.Returns(Task.CompletedTask)
.Callback<CreditCardApplication>(x => saveApplication = x);
var application = new NewCreditCardApplicationDetails()
FirstName = "Sarah",
LastName = "Smith",
Age = 18,
FrequentFlyerNumber = "012345-A",
GrossAnnualIncome = 100_000
;
await _sut.Index(application);
_mockRepository.Verify(
x => x.AddAsync(It.IsAny<CreditCardApplication>()), Times.Once);
Assert.Equal(application.FirstName, saveApplication.FirstName);
Assert.Equal(application.LastName, saveApplication.LastName);
Assert.Equal(application.Age, saveApplication.Age);
Assert.Equal(application.FrequentFlyerNumber, saveApplication.FrequentFlyerNumber);
Assert.Equal(application.GrossAnnualIncome, saveApplication.GrossAnnualIncome);
[Fact]
public async Task ReturnApplicationCompleteViewWhenValidModel()
var application = new NewCreditCardApplicationDetails()
FirstName = "Sarah",
LastName = "Smith",
Age = 18,
FrequentFlyerNumber = "012345-A",
GrossAnnualIncome = 100_000
;
var result = await _sut.Index(application);
var viewResult = Assert.IsType<ViewResult>(result);
Assert.Equal("ApplicationComplete", viewResult.ViewName);