首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发

如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发

作者头像
Zachary_ZF
发布2018-09-10 14:53:21
4990
发布2018-09-10 14:53:21
举报
文章被收录于专栏:跨界架构师跨界架构师

一、前言

实际编码已经写了2篇了,在这过程中非常感谢有听到观点不同的声音,借着这个契机,今天这篇就把大家提出的建议一个个的过一遍,重新整理,重新出发,为了让接下去的DDD之路走的更好。

二、单元测试

蟋蟀兄在我的第三篇文章下面指出:

这点其实是我偷懒了,单元测试其实不单单在DDD中是一个很重要的一环,在我们崇尚敏捷,快速迭代的大背景下,有良好的单元测试模块可以保证快速迭代下的项目质量。有甚至可以使用测试先行的TDD模式。

  单元测试的好处我就不多说了,那么现在开始在项目中增加单元测试。单元测试有多种命名方式,我个人的方式是给每一个对象单独建立一个测试类,然后里面每个单元测试方法的命名规则为"方法名_条件_预期的结果"这样子。那么根据我们之前的Cart和CartItem的建模,编写的单元测试如下:

    [TestClass]
    public class CartTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_CartIdDefault_ThrowArgumentException()
        {
            var cart = new Cart(default(Guid), Guid.NewGuid(), DateTime.Now);
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_UserIdDefault_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), default(Guid), DateTime.Now);
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_LastChangeTimeDefault_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), default(DateTime));
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        public void AddCartItem_NotExisted_TotalItemCountIsIncreased()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100));
            Assert.AreEqual(1, cart.TotalItemCount());

            cart.AddCartItem(new CartItem(new Guid("22222222-2222-2222-2222-222222222222"), 1, 100));
            Assert.AreEqual(2, cart.TotalItemCount());
        }

        [TestMethod]
        public void AddCartItem_Existed_TotalItemCountIsNotIncreasedTotalItemNumIsIncreased()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100));
            Assert.AreEqual(1, cart.TotalItemCount());
            Assert.AreEqual(1, cart.TotalItemNum());

            cart.AddCartItem(new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100));
            Assert.AreEqual(1, cart.TotalItemCount());
            Assert.AreEqual(2, cart.TotalItemNum());
        }
    }
    [TestClass]
    public class CartItemTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyQuantity_LessZero_ThrowArgumentException()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyQuantity(-1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyQuantity_EqualsZero_ThrowArgumentException()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyQuantity(0);
        }

        [TestMethod]
        public void ModifyQuantity_MoreZero_Success()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyQuantity(10);
            Assert.AreEqual(10, cartItem.Quantity);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyPrice_LessZero_ThrowArgumentException()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyPrice(-1);
        }

        [TestMethod]
        public void ModifyQuantity_EqualsZero_Success()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyQuantity(0);
            Assert.AreEqual(0, cartItem.Price);
        }

        [TestMethod]
        public void ModifyQuantity_MoreZero_Success()
        {
            var cartItem = new CartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            cartItem.ModifyQuantity(10);
            Assert.AreEqual(10, cartItem.Price);
        }
    }

三、纠正错误,重新出发

在写CartItemTest的时候发现了一个问题。领域对象的设计中有一个要点,就是实体必须需要通过其所属的聚合根才能访问,这样才能体现出聚合的的整体性,并且减少外界对聚合内部过多的了解。而目前对于CartItem的运用却有些背道而驰的意思,由外部对象进行实例化,必然增加了外部调用方对整个购物项构造过程的了解。有一位园友tubo有提到这点。

我思考了下,觉得这位园友的建议是对的。他建议的改法恰恰能够满足这个要求,隐藏了构造CartItem实体的细节。   好了那先把CartItem的构造函数访问类型设置为internal吧,这样也只能在CartItem所在的Domain项目中进行实例化了,然后再修改Cart.AddCartItem方法的参数。变为如下:

        public void AddCartItem(Guid productId, int quantity, decimal price)
        {
            var cartItem = new CartItem(productId, quantity, price);
            var existedCartItem = this._cartItems.FirstOrDefault(ent => ent.ProductId == cartItem.ProductId);
            if (existedCartItem == null)
            {
                this._cartItems.Add(cartItem);
            }
            else
            {
                existedCartItem.ModifyPrice(cartItem.Price); //有可能价格更新了,每次都更新一下。
                existedCartItem.ModifyQuantity(existedCartItem.Quantity + cartItem.Quantity);
            }
        }

单元测试也做出相应的更改:

    [TestClass]
    public class CartTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_CartIdDefault_ThrowArgumentException()
        {
            var cart = new Cart(default(Guid), Guid.NewGuid(), DateTime.Now);
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_UserIdDefault_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), default(Guid), DateTime.Now);
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void Constructor_LastChangeTimeDefault_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), default(DateTime));
            Assert.AreNotEqual(null, cart);
        }

        [TestMethod]
        public void AddCartItem_NotExisted_TotalItemCountIsIncreased()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            Assert.AreEqual(1, cart.TotalItemCount());

            cart.AddCartItem(new Guid("22222222-2222-2222-2222-222222222222"), 1, 100);
            Assert.AreEqual(2, cart.TotalItemCount());
        }

        [TestMethod]
        public void AddCartItem_Existed_TotalItemCountIsNotIncreasedTotalItemNumIsIncreased()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            Assert.AreEqual(1, cart.TotalItemCount());
            Assert.AreEqual(1, cart.TotalItemNum());

            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            Assert.AreEqual(1, cart.TotalItemCount());
            Assert.AreEqual(2, cart.TotalItemNum());
        }
    }
    [TestClass]
    public class CartItemTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyQuantity_LessZero_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(1, cartItem.Quantity);
            cartItem.ModifyQuantity(-1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyQuantity_EqualsZero_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(1, cartItem.Quantity);
            cartItem.ModifyQuantity(0);
        }

        [TestMethod]
        public void ModifyQuantity_MoreZero_Success()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(1, cartItem.Quantity);
            cartItem.ModifyQuantity(10);
            Assert.AreEqual(10, cartItem.Quantity);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ModifyPrice_LessZero_ThrowArgumentException()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(100, cartItem.Price);
            cartItem.ModifyPrice(-1);
        }

        [TestMethod]
        public void ModifyPrice_EqualsZero_Success()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(100, cartItem.Price);
            cartItem.ModifyPrice(0);
            Assert.AreEqual(0, cartItem.Price);
        }

        [TestMethod]
        public void ModifyPrice_MoreZero_Success()
        {
            var cart = new Cart(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now);
            cart.AddCartItem(new Guid("11111111-1111-1111-1111-111111111111"), 1, 100);
            var cartItem = cart.GetCartItem(new Guid("11111111-1111-1111-1111-111111111111"));
            Assert.AreNotEqual(null, cartItem);
            Assert.AreEqual(100, cartItem.Price);
            cartItem.ModifyPrice(10);
            Assert.AreEqual(10, cartItem.Price);
        }
    }

这样一来,被玻璃鱼儿netfocus2位园友所指出的奇怪的“UserBuyProductDomainService”也自然消失了。应用层代码变成:

        public Result Buy(Guid userId, Guid productId, int quantity)
        {
            var product = DomainRegistry.ProductService().GetProduct(productId);
            if (product == null)
            {
                return Result.Fail("对不起,未能获取产品信息请重试~");
            }

            var cart = _getUserCartDomainService.GetUserCart(userId);
            cart.AddCartItem(productId, quantity, product.SalePrice);
            DomainRegistry.CartRepository().Save(cart);
            return Result.Success();
        }

四、结语

DDD的道路是坎坷的,我希望通过在园子里发布的文章能够结交到志同道合的DDD之友,欢迎大家不吝啬自己的见解,多多留言,也让想学习或者正在学习DDD的园友少走一些弯路。

本文的源码地址:https://github.com/ZacharyFan/DDDDemo/tree/Demo5

作者:Zachary_Fan 出处:http://www.cnblogs.com/Zachary-Fan/p/6069169.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、单元测试
  • 三、纠正错误,重新出发
  • 四、结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档