将模拟概念应用于现实生活中的单元测试时大脑冻结
Brain freeze when applying mocking concepts to real-life unit test
我对与单元测试和模拟相关的概念很陌生。如果这是一个愚蠢的问题或我想出的例子来理解这些概念,请原谅我的无知。假设我有以下界面
public interface IMyService
{
OrderConfirmation ProcessOrder(Order order);
}
Order 和 OrderConfirmation class 定义如下。
public class Order
{
public int OrderId { get; set; }
public int CustomerId { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
}
public class OrderConfirmation
{
public int OrderConfirmationId { get; set; }
public int OrderId { get; set; }
public Shipment ShipmentDetails { get; set; }
}
public class Shipment
{
public int ShipmentId { get; set; }
public DateTime ShipmentDate { get; set; }
public int Cost { get; set; }
}
实现IMyService接口的class实现如下。这里的关键是它依赖于通过构造函数注入的数据提供者。
public class MyService : IMyService
{
private IDataProvider DataProvider;
public MyService(IDataProvider dataProvider)
{
DataProvider = dataProvider;
}
public OrderConfirmation ProcessOrder(Order request)
{
// bunch of operations here including calling various methods of DataProvider to save/retrieve data from databse.
}
}
IDataProvider 接口对 store/retrieve 数据库中的数据有一堆操作。
public interface IDataProvider
{
List<Product> GetAllProducts();
int CreateOrder(int customerId, List<Product> products);
int CreateOrderConfirmation(int OrderConfirmationId, int orderId);
void UpdateListOfAvailableProducts(List<Product> products);
}
为了测试 ProcessOrder 方法,似乎我必须以某种方式模拟 IDataProvider 接口的所有方法,但我真的很困惑如何提供模拟实现(使用)最小起订量。有人可以告诉我有关如何完成此操作的任何示例吗?
这是数据提供程序依赖项的模拟的许多假设示例之一。 但是请注意,没有看到测试方法的真正实现就说一些很模糊的事情。 HTH
[TestMethod]
public void ProcessOrder_WhenSomeTestedCondition_ThenCertainExpectedResult()
{
// Arrange
OrderConfirmation expectedResult = new OrderConfirmation(); // Set expected result here
Order fakeRequest = new Order();
List<Product> fakeProducts = new List<Product>();
int fakeCreateOrderResult = 123;
int fakeCreateOrderConfirmationResult = 456;
// This is the mocked dependency
Mock<IDataProvider> dataProviderMock = new Mock<IDataProvider>();
// Here the method is setup so it returns some fake products
dataProviderMock.Setup(dp => dp.GetAllProducts())
.Returns(fakeProducts);
// Here the method is setup so it returns some fake result
dataProviderMock.Setup(dp => dp.CreateOrder(It.IsAny<int>(), It.IsAny<List<Product>>()))
.Returns(fakeCreateOrderResult);
// Here the method is setup so it returns some fake result
dataProviderMock.Setup(dp => dp.CreateOrderConfirmation(It.IsAny<int>(), It.IsAny<int>()))
.Returns(fakeCreateOrderConfirmationResult);
// Here the method UpdateListOfAvailableProducts returns void so
// an example using callback is shouwing how the provided list of new products
// could update the existing ones
dataProviderMock.Setup(dp => dp.UpdateListOfAvailableProducts(
new List<Product> { new Product {Price = 100, ProductId = 1, ProductName = "Product_X"}}))
.Callback<List<Product>>(np =>
{
fakeProducts.AddRange(np);
});
// This is class under test which receives the mocked data provider object
MyService service = new MyService(dataProviderMock.Object);
// Act
// Here the tested method is executed
OrderConfirmation actualResult = service.ProcessOrder(fakeRequest);
// Assert
// Compare expected and actual results
Assert.AreEqual(expectedResult.OrderId, actualResult.OrderId);
}
我对与单元测试和模拟相关的概念很陌生。如果这是一个愚蠢的问题或我想出的例子来理解这些概念,请原谅我的无知。假设我有以下界面
public interface IMyService
{
OrderConfirmation ProcessOrder(Order order);
}
Order 和 OrderConfirmation class 定义如下。
public class Order
{
public int OrderId { get; set; }
public int CustomerId { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
}
public class OrderConfirmation
{
public int OrderConfirmationId { get; set; }
public int OrderId { get; set; }
public Shipment ShipmentDetails { get; set; }
}
public class Shipment
{
public int ShipmentId { get; set; }
public DateTime ShipmentDate { get; set; }
public int Cost { get; set; }
}
实现IMyService接口的class实现如下。这里的关键是它依赖于通过构造函数注入的数据提供者。
public class MyService : IMyService
{
private IDataProvider DataProvider;
public MyService(IDataProvider dataProvider)
{
DataProvider = dataProvider;
}
public OrderConfirmation ProcessOrder(Order request)
{
// bunch of operations here including calling various methods of DataProvider to save/retrieve data from databse.
}
}
IDataProvider 接口对 store/retrieve 数据库中的数据有一堆操作。
public interface IDataProvider
{
List<Product> GetAllProducts();
int CreateOrder(int customerId, List<Product> products);
int CreateOrderConfirmation(int OrderConfirmationId, int orderId);
void UpdateListOfAvailableProducts(List<Product> products);
}
为了测试 ProcessOrder 方法,似乎我必须以某种方式模拟 IDataProvider 接口的所有方法,但我真的很困惑如何提供模拟实现(使用)最小起订量。有人可以告诉我有关如何完成此操作的任何示例吗?
这是数据提供程序依赖项的模拟的许多假设示例之一。 但是请注意,没有看到测试方法的真正实现就说一些很模糊的事情。 HTH
[TestMethod]
public void ProcessOrder_WhenSomeTestedCondition_ThenCertainExpectedResult()
{
// Arrange
OrderConfirmation expectedResult = new OrderConfirmation(); // Set expected result here
Order fakeRequest = new Order();
List<Product> fakeProducts = new List<Product>();
int fakeCreateOrderResult = 123;
int fakeCreateOrderConfirmationResult = 456;
// This is the mocked dependency
Mock<IDataProvider> dataProviderMock = new Mock<IDataProvider>();
// Here the method is setup so it returns some fake products
dataProviderMock.Setup(dp => dp.GetAllProducts())
.Returns(fakeProducts);
// Here the method is setup so it returns some fake result
dataProviderMock.Setup(dp => dp.CreateOrder(It.IsAny<int>(), It.IsAny<List<Product>>()))
.Returns(fakeCreateOrderResult);
// Here the method is setup so it returns some fake result
dataProviderMock.Setup(dp => dp.CreateOrderConfirmation(It.IsAny<int>(), It.IsAny<int>()))
.Returns(fakeCreateOrderConfirmationResult);
// Here the method UpdateListOfAvailableProducts returns void so
// an example using callback is shouwing how the provided list of new products
// could update the existing ones
dataProviderMock.Setup(dp => dp.UpdateListOfAvailableProducts(
new List<Product> { new Product {Price = 100, ProductId = 1, ProductName = "Product_X"}}))
.Callback<List<Product>>(np =>
{
fakeProducts.AddRange(np);
});
// This is class under test which receives the mocked data provider object
MyService service = new MyService(dataProviderMock.Object);
// Act
// Here the tested method is executed
OrderConfirmation actualResult = service.ProcessOrder(fakeRequest);
// Assert
// Compare expected and actual results
Assert.AreEqual(expectedResult.OrderId, actualResult.OrderId);
}