Thoughts and practices on unit testing of draw a line

Source: Internet
Author: User
Tags xunit

This article originated from the question raised by a garden friend on my blog (how to perform unit tests on a drawing class). because there are no other classes or methods, we can use a few Asser statements. areequal (expectedvalue, actualvalue); To set assertions. The experience or experience of the author of this type of unit test is blank, so it is a pity that the author cannot solve the problem in a timely manner, but provides some suggestions based on the traditional unit test ideas.

General Unit Testing

Returned values

In general, the unit test we want to deal with is to deal with something similar to public objecta samplefunc (objectb param1, objectc param2 ){...}, for this type, xunit tools can be easily applied.

First, we prepare a batch of test data, including input and output data. Then, a group of input data (inputs []) corresponds to a group of expected output data (expectedoutput, finally, we can use the assert mentioned above:

Assert. areequal (expectedoutput, new samplefunc (inputs [0], inputs [1])

Then, make a pot of tea and run xunit. If it is green, it will be OK.

Changed some variables

This type of unit test objects-methods that change certain variables. Generally, they do not return values, but they may inadvertently shed clues, such as changing the value of a global variable, or insert a knife into a file record and leave a record. For example, if a method does not do anything, in addition to adding a piece of data to the database, you can also steal your ears and return a void, which is similar to the person who has nothing to do. The xunit series also supports this kind of method. If it's a big deal, you can check the victim and check the database to see the data you just added. Then you can use an assert to complete the process.

 

Unit test to be said today

The unit tests mentioned in the last few days have actually leaked the Tianji-unit tests on drawing-related methods, which are also called GUI unit tests. I think this name is strange, because most of the GUI tests I 've experienced previously were encountered in automated functional tests, but it is still a bit difficult to adapt to the GUI unit tests. To better illustrate this problem, I named it "draw a line" for unit testing. We will write a simple method. If we don't do anything bad, we will paint graffiti on the walls -- draw a line in the winform window, and then we will perform unit tests on this (class) method. It sounds interesting, and it seems not difficult. I thought so at first, but till now I have not been able to find a solution that satisfied myself. I cannot help but start to seriously doubt my own standards ~~

How can we conduct such unit tests? My first instinct at the time was-I really don't know ...... So I had to ask Google's teacher. Maybe I did not have a high search provider, but I only found several related articles. Then I couldn't quite understand a few of them, I sorted out a few articles I thought I understood, and then added some silly naive ideas.

Check log Method

This method is not listed first because it is a good method. On the contrary, it is because I am used to bitter and sweet. This unreliable method is used to let everyone throw bricks to test their tolerance. This method is to render the difficult drawing process, and then check the text to verify how we draw the graph.

For example, we have the following code:

Protected void drawaline (painteventargs E)
{
Graphics G = E. graphics;
Mypen. width = 5;
G. drawline (mypen, 16, 27, 38, 49 );
}

This method draws a line with a width of 5. The starting point is () and the ending point is (). For this method, we can add a piece of code at the end:

Protected void drawaline (painteventargs E)
{
Graphics G = E. graphics;
Mypen. width = 5;
G. drawline (mypen, 16, 27, 38, 49 );

Actionlog ("line (5) (16,27, 38,49)"); // in the log, we recorded a line with a width of 5 and a coordinate value of (16,27, 38,49)
}

The next thing is simple. Run the corresponding method in the test method, and then read the log to see if the log has done what we want to do.

Well, we can see that some people are beginning to scold "uncertain Fearless". In fact, this method is not only silly, but also has no practical use, and does not explain any problems. I racked my brains for such an application scenario:

// Draw a triangle

Protected void drawatri (painteventargs E)
{
Graphics G = E. graphics;
Mypen. width = 5;
G. drawline (mypen, 16, 27, 38, 49 );

Actionlog ("line (5) (16,27, 38,49)"); // in the log, we recorded 1st edges with a width of 5 and a coordinate value of (16,27, 38,49)

G. drawline (mypen, 38, 49, 54, 49 );

Actionlog ("line (5) (38, 49, 54, 49)"); // in the log, we recorded 2nd edges with a width of 5, the coordinate value is)

G. drawline (mypen, 54, 49, 16, 27 );

Actionlog ("line (5) (54, 49, 16, 27)"); // in the log, we recorded 3rd edges with a width of 5, the coordinate value is (54, 49, 16, 27)
}

In this way, we first read the log Content in the test code, and then gradually check what we did-draw the sequence of three sides, and even we can check whether the three sides are as wide as they are, are these three edges connected together (check whether the two vertices on either side are the same as one endpoint on the other ). In short, we present the invisible test code in the form of text, and then we can use the xunit tool to assert, green, then we're done.

But ...... We have to face that this method is indeed too limited and too obvious-this method has n major disadvantages:

1) it is too insecure. We cannot even ensure that our code is actually as written in log, it is very likely that we have not drawn a line, but a serious report in the log shows that we have drawn 2nd sides, the width is 5, the coordinate value is (16, 27,) and so on, this kind of false intelligence is likely to kill people.

2) When the assert is too complex, it is really complicated. to check whether the three sides are the same or not, we need two assert. to check whether the three sides are connected together, we need two assert...

3) code dependency at first glance is nothing more than adding a little log, but we may need to add Conditional compilation in the aftermath to prevent too much junk information from occupying resources. All these need to modify the source code, I believe that few people are willing to do this. In addition, when the number of source code increases, the complexity increases accordingly.

I twisted my brains once again and thought about the advantages of two methods:

1) tell us how our code is done, not what we do (that is, how rather than what)

2) Give us a little bit of self-deception (we tested these codes... You can see that the test coverage rate is there)

Simplified LOG method

This method is called the ultimate version mainly because we have adopted the method for the code to record its own behavior-we need to write a new graphics subclass called customgraphics, and then rewrite some of the methods, for example, in the drawline method, we may need to do this:

Public override void drawline (INT X1, int Y1, int X2, int Y2)

{

Base. drawline (INT X1, int Y1, int X2, int Y2 );

Actionlog ("drawline (INT" + X1

+ ", Int" + Y1

+ ", Int" + x2

+ ", Int" + y2

+ ")");

}

This may look better:

Public String actionsaveastext = "do nothing ";

Public override void drawline (INT X1, int Y1, int X2, int Y2)

{

Base. drawline (INT X1, int Y1, int X2, int Y2 );

Actionsaveastext = "drawline (INT" + X1

+ ", Int" + Y1

+ ", Int" + x2

+ ", Int" + y2

+ ")";

}

Other things are the same as those in the log method. This will obviously greatly reduce the number of actionlogs in the source code, but we also need to modify the code: we need to use customgraphics instead of the previous graphics class. We also need to ensure that the corresponding actionsaveastext = "... "; method, it seems that we are not much easier.

Notes:Well, I may have passed an error message to you. In fact, my test object is a function called drawaline, which can receive various parameters and draw a line, instead of testing. the existing drawline method in. Net does not need to be tested. Maybe I should change it to drawtwolines for testing. This will not cause misunderstanding ~~

 

Method

Okay, I have already finished talking about the above. I want to throw a brick and try to throw it. I just don't have the money to buy a house. Maybe I can make some bricks and build them on my own ~~ Next I will introduce it as another troublesome thing. From the perspective of the name, you may want to say: Is it true that the image is compared after the image is drawn. If you think so, congratulations. I did think so-I have been racking my brains twice, so I cannot find any better solution, you can only use this method to collect data.

The general idea is as follows:

Step 1: run the method drawaline to be tested and draw a line in the winform window.

Step 2: Check whether the drawn line is correct

Step 3: Save the line as an image

Step 4: Repeat the above operations in the test code and compare the images obtained in the test code with those obtained by manual running (debugging and running ).

The above steps are actually very similar to our common unit test process (of course, tests in TDD are not included here, but the order in which code is first tested in the traditional process ). Did we find silver bullet, and the problem was solved in this way? Obviously not that simple... However, to comfort me and everyone, let's look at the advantages of this method:

1) if the accuracy is improved by two identical images, we will naturally draw the correct picture, and we can also take the cut-down picture to have a good look, randomly check whether our drawaline is not on the mirror, whether the art photos are completely beyond the display-after all, what we need is draw's line.

2) less source code modification is another great advantage. Imagine that we just run the drawaline method. The drawaline method helps us draw a line, and then we take a picture to compare it with the previous standard image. We don't need to do anything else in the source code.

Seeing the above outlook, I felt a little excited. It seemed like a silver bullet. It was very good and very powerful... Okay, we should be awake after yy. We need to estimate the possible problems and the defects of this method in advance:

1) Can we capture the desired image after running the drawaline method and keep it consistent with the size and position of the standard image.

2) compare the two images to see if they are identical.

3) how to save standard images? How do we save standard images for different use cases? How can I save images during the test run for spot check?

4) The running speed is expected to be completed quickly for unit tests. Is there a problem with efficiency?

Mock Method

For many people, mock may be the best way to solve such problems. :) even when many articles about mock refer to mcok's best application environment, I don't forget to mention that unit testing related to UI is its strength. About the mock method, there are also some disadvantages, such as a rigid channel going to the dark-the implementation method of the original code is highly dependent, and the moss cannot meet the needs of some people, let them see the real running effect of the program.

In general, as the downstairs brother said, mock should be the best solution. As for the above method, it may seem a little bloated, it also looks like a functional test rather than a lightweight unit test.

Summary

After several days of intermittent sorting, I finally got a little eye off. For the third method, I already have some preliminary code. I believe I can share it with you in the next article. However, it is a pity that the author failed to find other more convenient methods. For example, if there is such a method, the result of drawaline can also be described as an object, then, compare the attributes of the object directly, or do other things and methods that I did not think? For the methods described above, you are welcome to throw bricks ~~

Postscript

Due to the crash of the development environment above, the Code in this article has not been debugged in the IDE, and the code may have some flaws or even weak syntax errors caused by negligence, the color of the Code is not as easy to identify as in Vs, so please forgive us for the difficulties caused by reading it ~~

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.