This is a creation in Article, where the information may have evolved or changed.
I tasted all day and thought, as a moment of learning also, I tasted go and hope, than ascend the Bo see also. Ascend and recruit, arm non-length also, and see Far, Shin, sound not add disease also, and smell. The false-Zhou Ji, the non-profit-footed, are thousands of miles away, and the false, the non-energy water, and the river. A gentleman is born non-dissimilar also, good false in things also.
--Xun Kuang "an exhortation"
Go language for unit testing is very important, and do not say other author background ah, open Source Library Ah, third-party support and so on, there are two points let me to Go language about unit testing of the degree of confidence in the point is:
- Unit test completeness of the Go language source code and the built-in library itself
- Go language comes with unit test commands
From these two points, I think the test is very important in the go language, so in this article, I'm also trying to say something about the Go language Unit test.
Write the Go Unit test code
The Go test method looks relatively low-level, relying on commands go test and some writing conventions that can be used to go test run test functions. However, I think this is the so-called go style, with go, my feeling is that the go language is to maintain the C language programming habits of a language.
First of all, in order to start this article, I write a simple function as an example to be tested later, but, considering that there may be some slightly more complicated things to say, so, this example I left some can change the place, we can choose to see:
This example is so simple, name the file main.go, and then we should write the test code. The location of the file where the test code is placed can be arbitrary package or arbitrary, but the file name must end with _test , so I'll name it main_test.go.
Here are some points to note about writing test functions:
- Each test file must end with _test.go , or the
go test test file cannot be found
- Each test file must be imported into the testing Package
- Function test function must start with test, and then generally the name of the testing function, this does not require
Based on these conditions, we can write a test file:
After the test file has been written, we should execute the test, open the command-line tool, and typing this command:go test main_test.go main.go -v -cover
Then you should wait for the test results, here Add two parameters, respectively, -v and -cover , if not added you will find only test Pass Simple hints, and do not see the specific hints we added parameters:
=== RUN TestAdd--- PASS: TestAdd (0.00s)PASScoverage: 50.0% of statementsok command-line-arguments 0.008s
Table-Based test methods
In the Go language, there is a commonly used test routines, called table-based testing methods , the core is that we need to target different scenarios, in fact, different inputs and outputs to verify a function. For example, we want to validate the Add function, we need to verify that there are many function points, for example:
- Two positive numbers are added correctly
- Two number of negative numbers are added correctly
- A positive number plus a negative number is correct
- There is a number of 0 is correct
So, we can use table-based testing , which the code can write:
Mock Dependency
The tests described earlier are simple and simple, so we can give the input directly and see if the output is as expected, so it's easy to finish the unit test. However, sometimes, due to the complexity of the business logic, the function code will not be so direct, often also doped many other components, which gives us a lot of trouble with the test work, I cite a few common dependencies:
- Component dependencies
- function dependency
Component dependencies and function dependencies are two common dependencies, but these two dependencies can also be extended, either from the components/functions we write ourselves, or by the introduction of others. But, no harm, we will do some analysis on these situations.
Component Dependency Processing
When using the Go language development project, we should often pull away from the component module, since the components and modules, so long dependent on the component, since there is a dependency, in the testing time we want to shield off the impact of dependent components, so that the better to test the details of the existing code; We want to control the behavior of dependent components based on our own test objectives. However, if we want to simply control input and output to control the behavior of dependent components, this difficulty is still relatively large, so in this case, we will generally consider passing a Stub component entry, so as to achieve the effect of controlling dependent component behavior.
To give an example, for example, our more common service layer and DAO layer operation, after the service processing logic, to the DAO layer to persist, or to call the DAO layer from the persistence to obtain some necessary data; Many times we don't want to really persist or get data from persistence, so we'll do some Mock-up of the DAO layer. First, let's give you a running example:
Here we want to test the correctness of the Service , but do not want to really persist DAO, so, this time we will create a Stub, and then provide to the service, we can also operate the DAO behavior, to achieve the effect of running, for example:
So we can test the login success of the code, login successful test, we also want to test the login failed, then it is very simple, modify it can be:
The test code is slightly changed here, we can find that we can modify a variable to control the output of the Stub, so as to achieve the effect of testing different functions, which solves the problem of component dependencies.
function dependency
function dependencies are a bit more cumbersome than component dependencies, as we can see earlier that component dependencies can be passed through stubs, so that we can arbitrarily control the behavior of the stub, but the function is not, and here we can't pass the function in, because the function is in the import. The problem is here, because the function is in the import, so it can be understood that the function is global, in this case, then why don't we modify the function? What do you mean? Let's look at the normal business example:
Here I would like to express the meaning of the need to log in, and then log in before we can reply to the message, here our login logic is simple, but in the actual business may be here in the login logic design to DB access and so on, we hope not to take the real logic, but to control Login the behavior ourselves.
First of all, we analyze our UT goal, our goal is to test the Reply function, we expect to be Login successful, it Reply should also be successful, if it Login fails, then it should be a Reply failure. This test conclusion should not be Login affected, in time after the Login logical modification, we should also be this logic, will not be affected, then we can write UT:
Here we can see that we are modifying the Login code of this function to control Login The return value of the function, so that we can test the logic of the code we wrote.
Perhaps the heart of the classmate found that the second function depends on the code there is a special place, because the function Login is a variable, why use a function variable, can not directly use the function? This is really a troublesome place, because if you use a direct function, we have no assignment, then we cannot modify it. If the code is not written by ourselves, but by the other colleagues ' code, then the problem is great. In this case, what can we do with it?
There is an article in the Reference: Mocking functions in Go describes a method that assigns a function variable to function variables and then uses it to achieve the same effect.
Third-party libraries
In the previous introduction, we have re-wrote a Stub class, but at the same time the problem is exposed, writing more complex and cumbersome, so there are some third-party library can be convenient for us to write these things, Gomock is a, here is a simple demonstration of gomock some of the features.
The Gomock has two components, namely Gomock and Mockgen. Mockgen can be based on our generation of the interface corresponding Stub objects, such as the DAO we mentioned earlier, because our DAO Interface has been written, so we can easily generate Stubdao, only need to use the command:
$ mockgen -source=main.go > mock_dao.go
Then we look at the contents of Mock_dao.go:
It can be found that two functions have been implemented ReadAll and SaveData , however, we have also found that the generated DAO is much more complex than we expected, and as to why the medicine is so complex, it is clear that the next use. Now that we have the DAO, the next step is to control the output of the DAO.
As you can see here, the use of Gomock can make our control output much easier, we need to control the variable to achieve the purpose of control output, but here it is very convenient to use:
d.EXPECT().FuncXXX.Return(xxxx)
It is really convenient to specify what the function should return, and it is worth a try to save the time for us to write our own mockclass.
Summarize
OK, this article about Go UT is almost so much, here is the Go unit test writing routines, as well as the introduction of some of our common scenarios in the project processing, and finally introduced a third library to speed up the preparation of UT. In my other article: looking at the Python unit test from an open source project, I mentioned that UT is something that we all want others to write, but that we don't want to write, and hopefully, a relatively simple way to write routines and patterns in the Go language allows you to focus on UT and be willing to write. lol
Reference
- Go programming language
- Mocking functions in Go