11 Study Notes of pro ASP. net mvc 3 framework [Use of Moq]

Source: Internet
Author: User

Use Moq

Previously I created a fakerepository class to support our tests, but I didn't create an actual repository implementation, so I need a replacement. The fakerepository class is a simulation implementation of the iproductrepository interface. Moq is a framework. In order to make it fast and easy to simulate, you do not need to manually add some additional code.

First, we need to download a Moq component. Click here to download it. Add a reference to Moq in productapp. Tests. The advantage of using the mocking tool is that we can create enough mocks to adapt to our functions to help test. We may not be able to understand the advantages of Moq in this project, but in actual projects, Moq allows us to easily achieve the mock implementation stage that requires our own testing, because Moq contains a wealth of code to help us implement it. We can create a lot of small manual mocks to make it work, and we can also move the code to a base class for reuse. But this will become complicated again. When the test can focus more on a certain point, it will make the test run better. Therefore, the simpler the test points, the better.

Two steps are required to create a mock using Moq,

First, create a new mock <t>, such as mock <iproductrepository> mock = new mock <iproductrepository> ();

Second, set the behavior to be explained for our implementation (behavior ). Moq automatically implements all methods and attributes of the given type, but uses the default values of the type.

For example, the iproductrepository. getproducts () method returns an empty ienumerable <product>. To change the mode in which Moq implements a type member, we must use the setup () method. As follows:

Product[] products = new Product[] 
{
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}
};

mock.Setup(m => m.GetProducts()).Returns(products);

 

When we create a new Moq behavior (behavior), we need to consider three factors:

First, select a method. moq uses the LINQ and lambda expressions. When we call a setup method, Moq will pass the interface we implement for it. These are cleverly wrapped in the LINQ and do not need to be further explored, however, Moq allows us to use a Lambda expression to select the method to be configured and verified. When we want to define an action for getproducts (), we can do this: mock. setup (M => M. getproducts ()). (Other methods); we don't have to worry about it. If it works, we only need to know how to use it. Here, the getproducts () method does not have a parameter, and the processing will be simpler.

When there is a parameter, I need to consider two factors: first, the parameter filter; we can let Moq make different responses based on different input parameters. For demonstration, an interface is added here:

public interface IMyInterface
{
string ProcessMessage(string message);
}

Then you can create the mock implementation of this interface based on different input parameters. As follows:

Mock<IMyInterface> mock = new Mock<IMyInterface>(); 
mock.Setup(m => m.ProcessMessage("hello")).Returns("Hi there");
mock.Setup(m => m.ProcessMessage("bye")).Returns("See you soon");

Here, when "hello" is passed in, "Hi there" is returned. If "bye" is passed in, "See you soon" is returned. For other parameters, a default value is returned, the default value here is null, because we use string-type parameters. It is easy to find that this method is very troublesome when dealing with complicated types, because we will create a lot of objects for presentation and comparison. Fortunately, Moq provides IT classes, allowing us to present a wide range of parameter values. For example: mock. setup (M => M. processmessage (it. isany <string> ())). returns ("Message received"); The it class defines many methods that use generic parameters. In this example, we can call the isany method and use string as a generic parameter. This allows Moq to know that when any string value is input to call the processmessage () method, it will return "Message received ed". This shows the list of methods provided by the IT class:

The following is an example of using the IT parameter filter, as shown below:

mock.Setup(m => m.ProcessMessage(It.Is<string>(s => s == "hello" || s == "bye"))).Returns("Message received");

This statement indicates that Moq returns "Message received ed" if the string parameter is "hello" or "bye"

When we set a behavior, we often define the returned results when a method is called. In the above Code, we link returns to the end of the method. We can also use the parameters passed into the mocked method as the returns () parameter, so that we can get an input-based output. The following code is used:

mock.Setup(m => m.ProcessMessage(It.IsAny<string>())).Returns<string>(s => string.Format("Message received: {0}", s));

 

The following code shows how to use Moq in a unit test:

[TestMethod] 
public void Correct_Total_Reduction_Amount() {

// Arrange
Product[] products = new Product[]
{
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}
};

Mock<IProductRepository> mock = new Mock<IProductRepository>();
mock.Setup(m => m.GetProducts()).Returns(products);
decimal reductionAmount = 10;
decimal initialTotal = products.Sum(p => p.Price);
MyPriceReducer target = new MyPriceReducer(mock.Object);

// Act
target.ReducePrices(reductionAmount);

// Assert
Assert.AreEqual(products.Sum(p => p.Price),(initialTotal - (products.Count() * reductionAmount)));
}

In the above Code, getproducts () is implemented to return our test data, and we put everything in a unit test method. In fact, we can use some test functions provided by Vs to make things easier. For example, we know that all the test methods will use the test object product, and all the initialization methods that can be created as a test class are as follows:

[Testclass]
Public class mypricereducertest
{
Private ienumerable <product> products;

[Testinitialize]// This feature allows the vs test function to initialize data.
Public void pretestinitialize ()
{

Products = new product [] {
New product () {name = "Kayak", price = 275 m },
New product () {name = "lifejacket", price = 48.95 m },
New product () {name = "soccer ball", price = 19.50 m },
New product () {name = "stadium", price = 79500 m}
};
}
......

In addition to the testinitialize (called before test execution) feature, the test function of vs also provides classinitialize (called before unit test execution and must be used for static methods ), classcleanup (called after all unit tests are executed, which must be used for static methods) and testcleanup (called after the test is executed ).

Verifying with Moq (Moq verification): one of our test rules is that the updateproduct () method is called by every product object. In the fakerepository class, we define
Auto-increment attributes. The Code is as follows:

        public void UpdateProduct(Product product)
{
foreach (Product p in products.Where(e => e.Name == product.Name).Select(e => e))
{
p.Price = product.Price;
}
UpdateProductCallCount++;
}

public int UpdateProductCallCount { get; set; }

Here we can use Moq to achieve the same effect in a more elegant way, as shown below:

// Act
Target. performanceprices (reduamoamount );

// Assert
Foreach (product P in products ){
Mock. Verify (M => M. updateproduct (P), times. Once ());// Verify that each product object calls the updateproduct () method once.
}
}

The three MVC tools have been introduced here, and the subsequent notes will go to a project instance.

Okay. Here are the notes for today.

Good night!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.