質問

I have a very basic MVC Controller but I can't figure out how to setup fakes for my Controller action. I'm new with this so any help would be great. I use EF 6.1, MVC 5.1 and .NET 4.5.1.

Controller:

public class MemberController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "Id,FirstName,LastName,BirthDay,MemberSince,Street,HouseNumber,Addition,ZipCode,City")] MemberCreateViewModel memberCreate)
    {
        if (ModelState.IsValid)
        {
            Mapper.CreateMap<MemberCreateViewModel, Member>();
            var member = Mapper.Map<Member>(memberCreate);

            db.Members.Add(member);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(memberCreate);
    }
}

Model:

public class MemberCreateViewModel
{

    [Display(Name = "Voornaam")]
    [Required]
    [StringLength(50)]
    public string FirstName { get; set; }

    [Display(Name = "Achternaam")]
    [Required]
    [StringLength(50)]
    public string LastName { get; set; }

    [Display(Name = "Geboortedatum")]
    [Required]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime BirthDay { get; set; }

    [Display(Name = "Lid sinds")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime MemberSince { get; set; }

    [Display(Name = "Straat")]
    [Required]
    [StringLength(100)]
    public string Street { get; set; }

    [Display(Name = "Huisnummer", ShortName = "Huisnr")]
    [Required]
    [Range(1, 5000)]
    public int HouseNumber { get; set; }

    [Display(Name = "Toevoeging")]
    public string Addition { get; set; }

    [Display(Name = "Postcode")]
    [Required]
    [StringLength(6, MinimumLength = 6)]
    public string ZipCode { get; set; }

    [Display(Name = "Plaats")]
    [Required]
    [StringLength(40)]
    public string City { get; set; }

    [Display(Name = "Telefoonnummer", ShortName = "Telnr")]
    [StringLength(10, MinimumLength = 10)]
    public string PhoneNumber { get; set; }

    [Display(Name = "Mobiel")]
    [StringLength(10, MinimumLength = 10)]
    public string MobileNumber { get; set; }

    [Display(Name = "E-mail")]
    [Required]
    [EmailAddress]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

}

Test method:

[TestMethod]
public void CreateSave()
{
    var mockSet = new StubDbSet<Member>();
    var mockContext = new StubApplicationDbContext()
    {   
    //Members = () =>
    //  {
    //      return new StubDbSet<Member>();
    //  }
    };

    // Arrange
    MemberController controller = new MemberController();

    MemberCreateViewModel vm = new MemberCreateViewModel()
    {
            Addition = "A",
            BirthDay = new DateTime(1995, 10, 14),
            City = "Rotterdam",
            Email = "test.user@fake.com",
            FirstName = "Test",
            HouseNumber = 4,
            LastName = "Persoon",
            MemberSince = new DateTime(2007, 10, 8),
            MobileNumber = "1234567890",
            PhoneNumber = "1234567890",
            Street = "Staartmanslaan",
            ZipCode = "3134kl"
    };

    // Act
    ViewResult result = controller.Create(vm) as ViewResult;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(result.ViewName, "Index");
}
役に立ちましたか?

解決

Finally got it to work. Succeed version:

[TestMethod]
    public void CreateMemberSucceededTest()
    {
        using (ShimsContext.Create())
        {               
            // Arrange
            var mockSet = new StubDbSet<Member>();

            ShimApplicationDbContext.Constructor = (t) => { };
            ShimApplicationDbContext.AllInstances.MembersGet = (t) =>
            {
                return mockSet;
            };
            ShimDbContext.AllInstances.SaveChanges = (t) => { return 1; };

            MemberController controller = new MemberController();

            MemberCreateViewModel vm = new MemberCreateViewModel()
            {
                Addition = "A",
                BirthDay = new DateTime(1995, 10, 14),
                City = "Rotterdam",
                Email = "test.user@fake.com",
                FirstName = "Test",
                HouseNumber = 4,
                LastName = "Persoon",
                MemberSince = new DateTime(2007, 10, 8),
                MobileNumber = "1234567890",
                PhoneNumber = "1234567890",
                Street = "Staartmanslaan",
                ZipCode = "3134kl"
            };

            // Act
            Validate(controller, vm);
            var result = controller.Create(vm) as RedirectToRouteResult;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(result.RouteValues["action"], "Index");
        }
    }

You also have to validate the object before submitting the viewModel to your crewate methode. If you don't do that your modelstate is always valid.

private static void Validate(MemberController controller, object entityToValidate)
    {
        var valResults = TryValidate(entityToValidate);
        SetErrorInModelState(valResults, controller);
    }

    internal static Collection<ValidationResult> TryValidate(object entityToValidate)
    {
        var result = new Collection<ValidationResult>();

        Validator.TryValidateObject(entityToValidate, new ValidationContext(entityToValidate, null, null), result, true);

        return result;
    }

    internal static void SetErrorInModelState(Collection<ValidationResult> validationErrors, Controller controller)
    {
        foreach (var validationError in validationErrors)
        {
            controller.ModelState.AddModelError(validationError.MemberNames.First(), validationError.ErrorMessage);
        }
    }

A version where in example the email is invalid: First a generic method for validating the method so we can use it for separate properties in the model:

private static void CreateMemberValidationTest(MemberCreateViewModel vm, string propertyThatFails)
    {
        using (ShimsContext.Create())
        {
            // Arrange
            var mockSet = new StubDbSet<Member>();

            ShimApplicationDbContext.Constructor = (t) => { };
            ShimApplicationDbContext.AllInstances.MembersGet = (t) =>
            {
                return mockSet;
            };
            ShimDbContext.AllInstances.SaveChanges = (t) => { return 1; };

            MemberController controller = new MemberController();

            // Act
            Validate(controller, vm);
            var result = controller.Create(vm) as ViewResult;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(result.ViewData.ModelState.Count, 1);
            Assert.AreEqual(result.ViewData.ModelState.Keys.First(), propertyThatFails);
        }
    }

And then the test that calls the method:

[TestMethod]
    public void CreateMemberNoEmailTest()
    {
        var vm = new MemberCreateViewModel()
        {
            Addition = "A",
            BirthDay = new DateTime(1995, 10, 14),
            City = "Rotterdam",
            Email = null,
            FirstName = "Test",
            HouseNumber = 4,
            LastName = "Persoon",
            MemberSince = new DateTime(2007, 10, 8),
            MobileNumber = "1234567890",
            PhoneNumber = "1234567890",
            Street = "Staartmanslaan",
            ZipCode = "3134kl"
        };

        CreateMemberValidationTest(vm, "Email");
    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top