Pro Aspnet MVC 4读书笔记(2) - The C# Auction Domain Model

Listing 3-1. The C# Auction Domain Model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class Member
    {
        public string LoginName { get; set; } // The unique key
        public int ReputationPoints { get; set; }
    }

    public class Bid
    {
        public Member Member { get; set; }
        public DateTime DatePlaced { get; set; }
        public decimal BidAmount { get; set; }
    }

    public class Item
    {
        public int ItemID { get; private set; } // The unique key
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime AuctionEndDate { get; set; }
        public IList<Bid> Bids { get; set; }
    }
}
View Code

Listing 3-2. C# Repository Classes for the Member and Item Domain Classes

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class MembersRepository
    {
        public void AddMember(Member member)
        { }

        public Member FetchByLoginName(string loginName)
        {
            return null;
        }

        public void SubmitChanges()
        { }
    }

    public class ItemsRepository
    {
        public void AddItem(Item item)
        { }

        public Item FetchById(int itemId)
        {
            return null;
        }

        public IList<Item> ListItems(int pageSize, int pageIndex)
        {
            return null;
        }

        public void SubmitChanges()
        { }
    }
}
View Code

Listing 3-3. Instantiating Concrete Classes to Get an Interface Implementation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class PasswordResetHelper
    {
        public void ResetPassword()
        {
            IEmailSender mySender = new MyEmailSender();

            // Call interface methods to configure e-mail details

            mySender.SendEmail();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public interface IEmailSender
    {
        void SendEmail();
    }

    public class MyEmailSender : IEmailSender
    {
        public void SendEmail()
        {
        }
    }
}
View Code

Listing 3-4. Removing Dependencies from the PasswordResetHelper Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class PasswordResetHelper
    {
        private IEmailSender _emailSender;

        public PasswordResetHelper(IEmailSender emailSender)
        {
            _emailSender = emailSender;
        }

        public void ResetPassword()
        {
            // Call interface methods to configure e-mail details
            _emailSender.SendEmail();
        }
    }
}
View Code

Listing 3-5. The IMembersRepository Interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public interface IMembersRepository
    {
        void AddMember(Member member);
        Member FetchByLoginName(string loginName);
        void SubmitChanges();
    }

    public class MembersRepository : IMembersRepository
    {
        public void AddMember(Member member)
        { }

        public Member FetchByLoginName(string loginName)
        {
            return null;
        }

        public void SubmitChanges()
        { }
    }
}
View Code

Listing 3-6. The AdminController Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcPattern.Models;

namespace MvcPattern.Controllers
{
    public class AdminController : Controller
    {
        IMembersRepository _membersRepository;

        public AdminController(IMembersRepository membersRepository)
        {
            _membersRepository = membersRepository;
        }

        public ActionResult ChangeLoginName(string oldLoginName, string newLoginName)
        {
            Member member = _membersRepository.FetchByLoginName(oldLoginName);
            member.LoginName = newLoginName;

            _membersRepository.SubmitChanges();

            return View();
        }
    }
}
View Code

Listing 3-7. An Example Test Fixture

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcPattern.Controllers;
using MvcPattern.Models;

namespace MvcPattern.Tests
{
    [TestClass]
    public class AdminControllerTest
    {
        [TestMethod]
        public void CanChangeLoginName()
        {
            // Arrange (set up a scenario)
            Member bob = new Member() { LoginName = "Bob" };
            FakeMembersRepository repository = new FakeMembersRepository();
            repository.Members.Add(bob);

            AdminController target = new AdminController(repository);

            string oldLoginName = bob.LoginName;
            string newLoginName = "Anastasia";

            // Act (attempt the operation)
            target.ChangeLoginName(oldLoginName, newLoginName);

            // Assert (verify the result)
            Assert.AreEqual(newLoginName, bob.LoginName);
            Assert.IsTrue(repository.DidSubmitChanges);

        }
    }

    private class FakeMembersRepository : IMembersRepository
    {
        public List<Member> Members = new List<Member>();
        public bool DidSubmitChanges = false;

        public void AddMember(Member member)
        {
        }

        public Member FetchByLoginName(string loginName)
        {
            return Members.First(m => m.LoginName == loginName);
        }

        public void SubmitChanges()
        {
            DidSubmitChanges = true;
        }
    }
}
View Code

Listing 3-8. Adding a Stub Method to the Item Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class Item
    {
        public int ItemID { get; private set; } // The unique key
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime AuctionEndDate { get; set; }
        public IList<Bid> Bids { get; set; }

        public void AddBid(Member member, Decimal amount)
        {
            throw new NotImplementedException();
        }
    }
}
View Code

Listing 3-9. Three Test Fixtures

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcPattern.Controllers;
using MvcPattern.Models;

namespace MvcPattern.Tests
{
    [TestClass]
    public class AdminControllerTest
    {
        [TestMethod]
        public void CanAddBid()
        {
            // Arrange - set up the scenario
            Item target = new Item();
            Member member = new Member();
            Decimal amount = 150M;

            // Act - perform the test
            target.AddBid(member, amount);

            // Assert - check the behavior
            Assert.AreEqual(1, target.Bids.Count());
            Assert.AreEqual(amount, target.Bids[0].BidAmount);
        }

        [TestMethod()]
        [ExpectedException(typeof(InvalidOperationException))]
        public void CannotAddLowerBid()
        {
            // Arrange
            Item target = new Item();
            Member member = new Member();
            Decimal amountParam = 150M;

            // Act
            target.AddBid(member, amountParam);
            target.AddBid(member, amountParam - 10);
        }

        [TestMethod()]
        public void CanAddHigherBid()
        {
            // Arrange
            Item target = new Item();
            Member firstMember = new Member();
            Member secondMember = new Member();
            Decimal amount = 150M;

            // Act
            target.AddBid(firstMember, amount);
            target.AddBid(secondMember, amount + 10);

            // Assert
            Assert.AreEqual(2, target.Bids.Count());
            Assert.AreEqual(amount + 10, target.Bids[1].BidAmount);
        }
    }
}
View Code

Listing 3-10. Implementing the AddBid Method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class Item
    {
        public int ItemID { get; private set; } // The unique key
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime AuctionEndDate { get; set; }
        public IList<Bid> Bids { get; set; }

        public Item()
        {
            Bids = new List<Bid>();
        }

        public void AddBid(Member member, Decimal amount)
        {
            Bids.Add(new Bid() { 
                BidAmount = amount,
                DatePlaced = DateTime.Now,
                Member = member
            });
        }
    }
}
View Code

Listing 3-11. Improving the Implementation of the AddBid Method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcPattern.Models
{
    public class Item
    {
        public int ItemID { get; private set; } // The unique key
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime AuctionEndDate { get; set; }
        public IList<Bid> Bids { get; set; }

        public Item()
        {
            Bids = new List<Bid>();
        }

        public void AddBid(Member member, Decimal amount)
        {
            if (Bids.Count == 0 || amount > Bids.Max(e => e.BidAmount))
            {
                Bids.Add(new Bid()
                {
                    BidAmount = amount,
                    DatePlaced = DateTime.Now,
                    Member = member
                });
            }
            else
            {
                throw new InvalidOperationException("Bid amount too low");
            }
        }
    }
}
View Code

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。