The previous notes are about ninject (the first IOC container in the three MVC tools). This note is about the use of the unit testing tool provided in Vs and Moq (simulation tool ).
1. Visual Studio built-in unit test tool
In addition to Microsoft's built-in unit testing tool, we can also choose nunit, a very popular testing tool. Next, we will create a project productapp. You can also use nunit and click here to get it. Its usage is very similar to that provided by.
First, we create a test class and interface, as shown below:
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { set; get; }
}
public interface IProductRepository
{
IEnumerable<Product> GetProducts();
void UpdateProduct(Product product);
}
public interface IPriceReducer
{
void ReducePrices(decimal priceReduction);
}
Here, the product class is the same as in the previous notes. The iproductrepository interface defines two methods: Get and update. This conforms to the repository mode, which we introduced in the previous notes. Ipricereducer defines a specific price reduction method for all products. Our goal is to implement this interface and meet the following conditions:
A. All products must be reduced.
B. The total price reduction must be equal to the product of the quantity of all products and the price reduction amount.
C. The updateproduct method of repository should be called by every product.
D. The prices of products after the price reduction cannot be less than 1
Next we will add a class to implement iproductrepository, as shown below:
public class FakeRepository : IProductRepository
{
private Product[] products = {
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
public IEnumerable<Product> GetProducts()
{
return products;
}
public void UpdateProduct(Product productParam)
{
foreach(Product p in products
.Where(e => e.Name == productParam.Name)
.Select(e => e)) {
p.Price = productParam.Price;
}
UpdateProductCallCount++;
}
public int UpdateProductCallCount { get; set; }
public decimal GetTotalValue()
{
return products.Sum(e => e.Price);
}
}
If you are not familiar with the query expression LINQ shown in 3.0 like me, I suggest you take the time to read the relevant information. I have been learning about this in the last five days, to help you learn MVC, and learn about LINQ, you will gradually like it. The ipricereducer interface is implemented as follows:
Public class mypricereducer: ipricereducer
{
Private iproductrepository repository;
Public mypricereducer (iproductrepository repo)
{
Repository = repo;
}
Public void performanceprices (decimal pricereduction)
{
// Do not implement it here
Throw new notimplementedexception ();
}
}
Here we can see DI again, and implement dependency injection through the constructor parameters (if you are unfamiliar with Di, you can take a look at my previous notes ).
Next, let's start the test. Create a test project. The method is very simple:
Right-click the method that we just did not implement to create a unit test. Next:
Unit test is in a separate project. We didn't create it here, so the dialog box for creating this test project will pop up. Let's name it: productapp. tests. after creation, a mypricereducertest is automatically created. CS class. Some methods are generated by default. The changes are as follows:
Namespace productapp. Tests
{
[Testclass]
Public class mypricereducertest
{
// Test whether all prices will change
[Testmethod]
Public void all_prices_are_changed)
{
// Arrange
Fakerepository repo = new fakerepository ();
Decimal reduamoamount = 10;
Ienumerable <decimal> prices = Repo. getproducts (). Select (E => E. Price );
Decimal [] initialprices = prices. toarray ();
Mypricereducer target = new mypricereducer (repo );
// Act
Target. performanceprices (reduamoamount );
// Merge two sequences (the new extension method provided in 4.0)
// Compare the starting price with the price after the price reduction. If the price is equal, the price reduction fails.
Prices. Zip (initialprices, (P1, P2) => {
If (p1 = P2 ){
Assert. Fail ();
}
Return P1;
});
}
}
}
Here we can find that some attributes (attributes) are marked in the test method, such as [testmethod] and [testclass]. If the classes in the test project do not include the classes and methods of these features, they will not be tested, and Vs will ignore them. We can find that the unit test is performed in the arrange/Act/assert mode. Arrange: the initialization test environment is in the preparation stage; Act: executes the test; Assert: asserted, the test result. There are many kinds of conventions for the test method. Here we are simple. Through the method name, we can know what the test content is. In fact, if you do not like big data, you can choose your own method or team agreement, mainly for developers to understand.
There are many different ways to create a unit test. A common method is to test all scenarios of a function in a method. Here we tend to scatter many different situations into a small test method. This test continuously improves the development mode of our code to become TDD (test-driven development). Then we create a test method. The Code is as follows:
[TestMethod]
public void Correct_Total_Reduction_Amount()
{
// Arrange
FakeRepository repo = new FakeRepository();
decimal reductionAmount = 10;
decimal initialTotal = repo.GetTotalValue();
MyPriceReducer target = new MyPriceReducer(repo);
// Act
target.ReducePrices(reductionAmount);
// Assert
Assert.AreEqual(repo.GetTotalValue(),(initialTotal - (repo.GetProducts().Count() * reductionAmount)));
}
[TestMethod]
public void No_Price_Less_Than_One_Dollar()
{
// Arrange
FakeRepository repo = new FakeRepository();
decimal reductionAmount = decimal.MaxValue;
MyPriceReducer target = new MyPriceReducer(repo);
// Act
target.ReducePrices(reductionAmount);
// Assert
foreach (Product prod in repo.GetProducts()) {
Assert.IsTrue(prod.Price >= 1);
}
}
The above two testing methods should be easy to understand. Dependency injection is also implemented here, and it is a constructor injection. There are many other static assert methods. We can click here to learn more. Each static method allows us to test a unit test. If assert fails, an exception is thrown, which means the entire unit test fails. Each unit test is independent, and other unit tests are not stopped because of the failure of a unit test.
Each static method of assert has an overloaded method with the string parameter. This parameter contains the exception information when the assert fails. It is worth noting that this predictionexpected feature is an asserted that only when a specific type exception is thrown by a parameter of the exception type in unit test. This is a very clever way, it ensures that the exception throws do not need to be mixed into our test code try... catch.
Next we will run the test, and an error will be reported, because we have not implemented it yet? The Code is as follows:
Public class mypricereducer: ipricereducer
{
Private iproductrepository repository;
Public mypricereducer (iproductrepository repo)
{
Repository = repo;
}
Public void performanceprices (decimal pricereduction)
{
Foreach (product P in repository. getproducts ())
{
P. Price = math. Max (P. Price-pricereduction, 1); // you can reduce the price and ensure that the price of each product is no less than 1 RMB.
Repository. updateproduct (P );
}
}
}
Once again, please note that the black part has implemented constructor injection.
Now, the note is here. Today, we mainly introduced the test tools provided by Vs, which are easy to understand. I didn't plan to take this part of the note, but I wrote it to keep the whole note coherent. If you are familiar with the test, I am sorry to waste your time. There is also an introduction to the Moq tool, followed by a small application: sportsstore.
The notes will certainly be inaccurate or incorrect. Please give me more guidance and help. Thank you!
Good night!