有没有办法在服务中模拟使用 Moq 服务并执行代码?

如何解决有没有办法在服务中模拟使用 Moq 服务并执行代码?

我有一个使用 Moq 的测试问题。我到处都看过,但我不太明白到底发生了什么。

我想测试一个名为 Basket 的类(服务),在该类中我作为 DI 传递另一个类(服务)discountService。

我面临的问题是,每当我模拟 Basket 类时,它都会很好地触发,但是当它到达在 discountService 中实际执行另一个方法代码时,它只是跳过该方法而不是进入。做错了吗?

我想可能是我没有正确地进行设置?

这是我目前的实际测试代码

 [Test]
        public async System.Threading.Tasks.Task Test1Async()
        {
            //Arrange
            var basketServiceMock = new Mock<IBasket>();
            var discountServiceMock = new Mock<IdiscountService>();

            List<BasketProductModel> productsModel = 
                new List<BasketProductModel> 
                { 
                    new BasketProductModel()
                    {
                        ProductName = "Milk",ProductPrice = 10,Quantity = 3
                    }
                };
            BasketModel basket = new BasketModel { Products = productsModel };
            basketServiceMock.Setup(x => x.Baskett)
                .Returns(new BasketModel { Products = productsModel });

            var product = new BasketProductModel()
            {
                ProductName = "Milk",Quantity = 1
            };
            var product1 = new BasketProductModel()
            {
                ProductName = "Milk",Quantity = 1
            };
            var product2 = new BasketProductModel()
            {
                ProductName = "Milk",Quantity = 1
            };
            var product3 = new BasketProductModel()
            {
                ProductName = "Milk",Quantity = 1
            };

            discountServiceMock.Setup(x => x.Applydiscount(ref basket,product));
            var basketService = new Basket.Basket(discountServiceMock.Object);


            //Act
            await basketService.AddProductToBasket(product);
            await basketService.AddProductToBasket(product1);
            await basketService.AddProductToBasket(product2);
            await basketService.AddProductToBasket(product3);

            //Assert

        }

这是我的篮子类:

       public class Basket : IBasket
    {
        private BasketModel _basketProducts;
        private double _totalCost;
        public BasketModel Baskett { 
            get {
                if (_basketProducts == null)
                    throw new ArgumentNullException("xxxxxxxxxx");

                return _basketProducts;
            } 
        }

        public double TotalCost
        {
            get
            {
                if (_totalCost == null)
                {
                    throw new ArgumentNullException("xxxxxxxxxx");
                }

                return _totalCost;
            }
        }

        private readonly IdiscountService _discountService;

        public Basket(IdiscountService discountService)
        {
            _discountService = discountService;

            _basketProducts = new BasketModel();
            _basketProducts.Products = new List<BasketProductModel>();
        }

        public async Task AddProductToBasket(BasketProductModel product)
        {
            if (product == null)
                throw new ArgumentNullException();


            var obj = _basketProducts.Products.FirstOrDefault(x => x.ProductName == product.ProductName);
            if (obj == null)
                _basketProducts.Products.Add(product);
            else
            {
                obj.Quantity += product.Quantity;
            }
            _discountService.Applydiscount(ref _basketProducts,product); <---This part is being skipped,do I miss something in the SETUP part?!

        }


    }

这是我的 discountService 类,它没有被触发(Applydiscount 方法

       public class discountService : IdiscountService
    {

        public static readonly ReadOnlyCollection<string> discountedProducts = new List<String> {
                                                                                            "Milk","Butter","Bread",}.AsReadOnly();

        public void Applydiscount(ref BasketModel basket,BasketProductModel product)
        {
            if (discountedProducts.Contains(product.ProductName) && basket.Products.Count > 0)
                product.Calculatediscount(basket);
        }

    }

这是 BasketProductModel(篮子里的产品)

    public class BasketProductModel : discountProcess
    {
        public BasketProductModel()
        {
            Init(this);
        }

        public string ProductName { get; set; }
        public double ProductPrice { get; set; }
        public int Quantity;
        public int Freebies { get; set; }
        public double Total { get; set; }
    }

这是上面类中使用的抽象类,用于使用一些预先配置的实现


    public abstract class discountProcess
    {
        private BasketProductModel _obj { get; set; }
        public BasketProductModel Obj
        {
            get
            {    // check _obj is inited:
                if (_obj == null) throw new Exception();
                return _obj;
            }
        }

        protected void Init(BasketProductModel bPModel)
        {
            _obj = bPModel;
        }

        public void Calculatediscount(BasketModel basket)
        {
            var productContained = NumberOfProductsInBasket(ref basket,_obj);
            var obj = basket.Products.FirstOrDefault(x => x.ProductName == _obj.ProductName);

            var freeItems = 0;
            switch (_obj.ProductName)
            {
                case "Milk":
                    if (productContained % 2 != 0)
                    {
                        obj.Freebies = numberOfFreeItems(obj.Quantity);
                        //AddQuantity(ref obj);
                    }
                    break;
                case "Butter":

                    break;
                case "Bread":
                    productContained = NumberOfProductsInBasket(ref basket,productName: "Butter");
                    if (productContained % 2 == 0)
                    {
                        CalculatediscountedPrice(50,ref obj);
                    }
                    break;
                default:
                    break;
            }

            Calculatetotal(ref obj);
        }

        //...Other Methods...
    }

所以基本上我甚至希望能够访问服务内部的代码并执行所有代码,以便我可以断言篮子:)

知道如何实现这一点吗?

最终目标:

我希望 Baskett 拥有基于 discountService 对 ref 传递的 basked 所做的操作的数据,以便我最终可以断言。

解决方法

如果 Basket 是被测对象,则不应嘲笑它。

//...

//Arrange
var basketServiceMock = new Mock<IBasket>(); //<-- Should not be mocked
var discountServiceMock = new Mock<IDiscountService>();

//...

相反,使用实际实例,

var discountServiceMock = new Mock<IDiscountService>();
Basket basketServiceMock = new Basket(discountServiceMock .Object);

//...

并模拟完成测试用例所需的依赖项。

本例中的主题在其构造函数中初始化模型,您尝试在测试中设置该模型。由于模型是由主题类初始化的,因此无需在测试中尝试创建一个。只需根据测试需要填充它。

查看以下内容

[Test]
public async System.Threading.Tasks.Task Test1Async() {
    //Arrange
    
    var discountServiceMock = new Mock<IDiscountService>();

    Basket subject = new Basket(discountServiceMock.Object);

    List<BasketProductModel> productsModel = new List<BasketProductModel> { 
        new BasketProductModel() {
            ProductName = "Milk",ProductPrice = 10,Quantity = 3
        }
    };
    subject.Baskett.Products =  productsModel; 
    
    // Only matches if the ref argument to the invocation is the same instance
    discountServiceMock
        .Setup(x => x.ApplyDiscount(ref subject.Baskett,It.IsAny<BasketProductModel>()));
        //You need to decide what you want the mocked member to do.
    
    var product = new BasketProductModel() {
        ProductName = "Milk",Quantity = 1
    };
    var product1 = new BasketProductModel() {
        ProductName = "Milk",Quantity = 1
    };
    var product2 = new BasketProductModel() {
        ProductName = "Milk",Quantity = 1
    };
    var product3 = new BasketProductModel() {
        ProductName = "Milk",Quantity = 1
    };

    //Act
    await subject.AddProductToBasket(product);
    await subject.AddProductToBasket(product1);
    await subject.AddProductToBasket(product2);
    await subject.AddProductToBasket(product3);

    //Assert
    //...You need to decide what it is you are actually testing
    //and want to assert

}

观察:

被测成员被定义为 async,但该成员实际上没有等待。重新检查该成员的设计。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?