Recently, some have adopted the TDD method to develop a module. I will summarize the gains from some of them:
1. The basic principles of TDDThe core idea of TDD is to first clarify the requirements, quantify them in code, clarify the requirements standards, and then encode them to achieve the standards measured by code testing.
Then it requires that the required standards be written first, and only one at a time is written. The encoding is achieved through the implementation and just meets this standard. This is iterating little by little.
There are three benefits to this: one is to clarify the standards first so that we will not lose our theme or deviate from the direction. There are standards to check to ensure that the code is correct. Only meet current tests and do not optimize prematurely and over-design.
2. TDD's Difficulties
The difficulty lies in how to design this test standard.
1) Make it small enough to be a demand unit;
2) Become a standard, that is, how to detect correctness;
3) It is how to simulate the real running scenario to the greatest extent, rather than writing many additional tools for testing, that is, the test should be the same as the real project code and there should be no unnecessary things.
The key is to analyze and explore requirements and refine requirements. If you test some APIs like the examples in the book, it is easy to write, because the test code calls the API in the same way as the real App code, and the functions of the API will also be clearly described. But the reality is not the case. For example, many frameworks are difficult to test, and many objects, creation and control are done by frameworks, and you cannot control them like you. This makes it difficult to write test cases.
There is also multi-threading. Due to the uncertainty brought by threads, there are many pseudo-failures. This can be used as a reference book, and there are methods in the book.
3. TDD in Android
To be honest, it is impossible to fully use the TDD method to develop on Android. The reasons are as follows:
1. The main structure of applications in Android is four major components: Service, Activity, the creation and destruction of four things: Provider and Receiver are controlled by the framework. So you can't test them like the examples in the book, because there are some limitations that you can't test with code.
2. Some things are callbacks to the system framework or very basic things that don’t need to write TestCase at all. For example, the processing of the Click/LongClick/Touch event of View, or the life cycle callback of the Activity, or the OptionsMenu/ContextMenu, etc.
3. The API function used for testing in the SDK is too weak
This leads to a lot of work and writing a lot of code in order to test a small function, which is much greater than direct implementation. For example, if you test a pop-up Dialog, it is easy to implement it directly; but if you use code to test it, it will take 3 or 4 times more workload, which is much greater than the direct implementation.
4. So how should TDD be used well in Android?Here are some suggestions:
1. Use Robotium
This is a powerful tool, which is much more convenient than the things in the SDK, such as searchText, clickMenu, and other interfaces, which are very convenient and practical.
2. Automatic testing + manual testing
The same principle must be followed, but for test cases, it is not necessary to write them completely in code. Partially manual testing can be tested: in general, if automatic testing is more convenient, write TestCase, and if manual testing is very convenient, test manually. There is no dead rule to depend on the specific situation.
For example, interaction-related things like View events, Activity events, Activity Menu, Dialog, etc., as well as cross-application interaction use cases, it is best to test these things manually, because they are more troublesome to use code to test them.
But for some numerical values, calculations, quantization, etc., you use code to do it. For example, after downloading a file, you can directly use the File object to detect whether the file is downloaded successfully.
3. Provider must be tested
Provider provides an API, which is very easy to test and easy to write. It is also a basic facility for a project, so it must be tested carefully. Otherwise, if there is a problem with a certain piece of data in the Activity, you must determine whether there is a problem with the display or a problem in the Provider. Usually CRUD must be tested, there is also where statements, and reverse tests, the legality of Uri must be detected, etc., and the processing of special characters, such as ' and ".
4. Except Service and ActivityOther things, especially those similar to APIs that you implement, should also be tested if some business logic is involved. This is similar to the examples in the book. The difficulty of testing depends on the degree of business decomposition, design and coupling.
5. Use reflection to test the inner part of the class
Although Service and Activity can be obtained in TestCase, Service and Activity are a component unit that does not actually publicize too many interfaces. They are at the top to call other interfaces, and they do not, and they should not disclose the interfaces for others to use. The reason is that their creation and life cycle management are controlled by the system, and there should not be too many references to them elsewhere.
So what should I do when I want to test the service and activity internals? For example, you want to test an int[] mPlaylistQueue inside a Service. We can't add interfaces to the Service to write Case! At this time, you need to use the reflection mechanism to retrieve the instance of this member and then check its data.
6. Some things must be tested manually and automation cannot be completed
TestCase has special Context and MockObject. It is a maximized simulation of real Android running. It is not exactly the same as when the application is actually running! And due to Permission, some things cannot be done in Instrumentation, such as Alarm, date, etc. Instrumentation has no permissions to change. These must be tested manually.
There is also the initialization and destruction of Service and Activity, especially the destruction, and there is no way to test it. In other words, it is really difficult to test the things in onDestroy(). First, you don't know when it was called back; second, when the object is executed to it, the reference you hold may not be valid; third, it is impossible to know whether the member objects are valid. For onDestroy, you can only manually test it through debugging.
In short, in my opinion, the core idea of TDD is to test first and implement it later. However, there is no requirement to use code for testing, so based on the actual situation, choose the best testing method.
1. The basic principles of TDDThe core idea of TDD is to first clarify the requirements, quantify them in code, clarify the requirements standards, and then encode them to achieve the standards measured by code testing.
Then it requires that the required standards be written first, and only one at a time is written. The encoding is achieved through the implementation and just meets this standard. This is iterating little by little.
There are three benefits to this: one is to clarify the standards first so that we will not lose our theme or deviate from the direction. There are standards to check to ensure that the code is correct. Only meet current tests and do not optimize prematurely and over-design.
2. TDD's Difficulties
The difficulty lies in how to design this test standard.
1) Make it small enough to be a demand unit;
2) Become a standard, that is, how to detect correctness;
3) It is how to simulate the real running scenario to the greatest extent, rather than writing many additional tools for testing, that is, the test should be the same as the real project code and there should be no unnecessary things.
The key is to analyze and explore requirements and refine requirements. If you test some APIs like the examples in the book, it is easy to write, because the test code calls the API in the same way as the real App code, and the functions of the API will also be clearly described. But the reality is not the case. For example, many frameworks are difficult to test, and many objects, creation and control are done by frameworks, and you cannot control them like you. This makes it difficult to write test cases.
There is also multi-threading. Due to the uncertainty brought by threads, there are many pseudo-failures. This can be used as a reference book, and there are methods in the book.
3. TDD in Android
To be honest, it is impossible to fully use the TDD method to develop on Android. The reasons are as follows:
1. The main structure of applications in Android is four major components: Service, Activity, the creation and destruction of four things: Provider and Receiver are controlled by the framework. So you can't test them like the examples in the book, because there are some limitations that you can't test with code.
2. Some things are callbacks to the system framework or very basic things that don’t need to write TestCase at all. For example, the processing of the Click/LongClick/Touch event of View, or the life cycle callback of the Activity, or the OptionsMenu/ContextMenu, etc.
3. The API function used for testing in the SDK is too weak
This leads to a lot of work and writing a lot of code in order to test a small function, which is much greater than direct implementation. For example, if you test a pop-up Dialog, it is easy to implement it directly; but if you use code to test it, it will take 3 or 4 times more workload, which is much greater than the direct implementation.
4. So how should TDD be used well in Android?Here are some suggestions:
1. Use Robotium
This is a powerful tool, which is much more convenient than the things in the SDK, such as searchText, clickMenu, and other interfaces, which are very convenient and practical.
2. Automatic testing + manual testing
The same principle must be followed, but for test cases, it is not necessary to write them completely in code. Partially manual testing can be tested: in general, if automatic testing is more convenient, write TestCase, and if manual testing is very convenient, test manually. There is no dead rule to depend on the specific situation.
For example, interaction-related things like View events, Activity events, Activity Menu, Dialog, etc., as well as cross-application interaction use cases, it is best to test these things manually, because they are more troublesome to use code to test them.
But for some numerical values, calculations, quantization, etc., you use code to do it. For example, after downloading a file, you can directly use the File object to detect whether the file is downloaded successfully.
3. Provider must be tested
Provider provides an API, which is very easy to test and easy to write. It is also a basic facility for a project, so it must be tested carefully. Otherwise, if there is a problem with a certain piece of data in the Activity, you must determine whether there is a problem with the display or a problem in the Provider. Usually CRUD must be tested, there is also where statements, and reverse tests, the legality of Uri must be detected, etc., and the processing of special characters, such as ' and ".
4. Except Service and ActivityOther things, especially those similar to APIs that you implement, should also be tested if some business logic is involved. This is similar to the examples in the book. The difficulty of testing depends on the degree of business decomposition, design and coupling.
5. Use reflection to test the inner part of the class
Although Service and Activity can be obtained in TestCase, Service and Activity are a component unit that does not actually publicize too many interfaces. They are at the top to call other interfaces, and they do not, and they should not disclose the interfaces for others to use. The reason is that their creation and life cycle management are controlled by the system, and there should not be too many references to them elsewhere.
So what should I do when I want to test the service and activity internals? For example, you want to test an int[] mPlaylistQueue inside a Service. We can't add interfaces to the Service to write Case! At this time, you need to use the reflection mechanism to retrieve the instance of this member and then check its data.
6. Some things must be tested manually and automation cannot be completed
TestCase has special Context and MockObject. It is a maximized simulation of real Android running. It is not exactly the same as when the application is actually running! And due to Permission, some things cannot be done in Instrumentation, such as Alarm, date, etc. Instrumentation has no permissions to change. These must be tested manually.
There is also the initialization and destruction of Service and Activity, especially the destruction, and there is no way to test it. In other words, it is really difficult to test the things in onDestroy(). First, you don't know when it was called back; second, when the object is executed to it, the reference you hold may not be valid; third, it is impossible to know whether the member objects are valid. For onDestroy, you can only manually test it through debugging.
In short, in my opinion, the core idea of TDD is to test first and implement it later. However, there is no requirement to use code for testing, so based on the actual situation, choose the best testing method.