complete the english doc

This commit is contained in:
金戟 2020-12-24 16:14:18 +08:00
parent 44fed6ce8b
commit 7f73fc0cc1
9 changed files with 137 additions and 16 deletions

View File

@ -14,7 +14,7 @@ Usage Document: https://alibaba.github.io/testable-mock/#/en-us/
|-- testable-all ➜ Dependence aggration, for easily import all modules at once
|-- testable-processor ➜ Compile-time code preprocessing module, provides test assist functions
|-- testable-agent ➜ JavaAgent module, provides test mocking related functions
|-- testable-core ➜ Basic function module, provides Mock related class and annotation
|-- testable-core ➜ Basic function module, provides mock related class and annotation
|-- testable-maven-plugin ➜ Maven plugin module, for simplify JavaAgent injection
|-- demo
| |-- java-demo ➜ Java code example

View File

@ -1,11 +1,11 @@
TestableMock Introduction
---
The Mock method in unit testing is usually to bypass method calls that rely on external resources or irrelevant functions, so that the focus of the test can be keep on the code logic that needs to be verified and guaranteed.
The mock method in unit testing is usually to bypass method calls that rely on external resources or irrelevant functions, so that the focus of the test can be keep on the code logic that needs to be verified and guaranteed.
When defining the Mock method, the developer really cares about only one thing: "<u>This call should be replaced with the fake **mock method** during testing</u>".
When defining the mock method, developers really care about only one thing: "<u>This call should be replaced with the fake **mock method** during testing</u>".
However, when the current mainstream Mock framework implements the Mock function, developers have to worry about too many things: how the Mock framework is initialized, whether it is compatible with the unit testing framework used, whether the method to be mocked is private or static, whether the Mock object is created by `new` operator or injected, how to send the mock object back to the class under test... These non-critical additional tasks greatly distract the fun of using the mock tool.
However, when the current mainstream mock framework implements the mock function, developers have to worry about too many things: how the mock framework is initialized, whether it is compatible with the unit testing framework used, whether the method to be mocked is private or static, whether the object to be mocked is created by `new` operator or injected, how to send the mock object back to the class under test... These non-critical additional tasks greatly distract the fun of using the mock tool.
Therefore, we developed `TestableMock`, **a maverick and lightweight mock tool**.

View File

@ -1,9 +1,9 @@
Mock Tools Comparison
---
Besides `TestableMock`, there are also several other community Mock tools, such as `Mockito`, `Spock`, `PowerMock` and `JMockit`. Comparison as follows:
Besides `TestableMock`, there are also several other community mock tools, such as `Mockito`, `Spock`, `PowerMock` and `JMockit`. Comparison as follows:
| Tool | Mechanism | Minimal Mock Unit | Limitation of method be mocked | Ease of use | IDE support |
| Tool | Mechanism | Minimal mock unit | Limitation of method be mocked | Ease of use | IDE support |
| ---- | ---- | ---- | ---- | ---- | ---- |
| Mockito | Dynamic proxy | Class | Except private/static method and constructor | **Easy** | **Very well** |
| Spock | Dynamic proxy | Class | Except private/static method and constructor | Complicate | Just so so |

View File

@ -5,11 +5,11 @@ Frequently Asked Questions
Create the class under test object directly, and then use the ability of `TestableMock` to access private members to directly assign values to these fields.
#### 2. Can `TestableMock` be used with other Mock tools?
#### 2. Can `TestableMock` be used with other mock tools?
`TestableMock` can be safely used together with other Mock tools based on dynamic proxy mechanism, such as `Mockito`, `EasyMock`, `Spock`, etc., all belong to this category.
`TestableMock` can be safely used together with other mock tools based on dynamic proxy mechanism, such as `Mockito`, `EasyMock`, `Spock`, etc., all belong to this category.
For Mock tools that modify the class loader or the bytecode of the class under test, such as `PowerMock` and `JMockit`, there is no yet case to prove that they will conflict with `TestableMock`, but in principle, there may be a risk of incompatibility between the two, Please use with caution.
For mock tools that modify the class loader or the bytecode of the class under test, such as `PowerMock` and `JMockit`, there is no yet case to prove that they will conflict with `TestableMock`, but in principle, there may be a risk of incompatibility between the two, Please use with caution.
#### 3. How to implement the mock method when the parent class variable points to the child class object?
@ -17,13 +17,13 @@ In the code, there are often cases of using <u>interface variables or parent cla
At this time, follow a principle that the type of the first parameter of the mock method is always the same as the type of the variable that initiated the call.
Therefore, regardless of whether the actually called method comes from the parent class or the subclass, and whether the subclass overrides the method. If the calling variable is of the parent type (or interface type), the first parameter type of the Mock method should use the corresponding parent type (or interface) type.
Therefore, regardless of whether the actually called method comes from the parent class or the subclass, and whether the subclass overrides the method. If the calling variable is of the parent type (or interface type), the first parameter type of the mock method should use the corresponding parent type (or interface) type.
See the use case of the `DemoInheritTest` test class in the Java and Kotlin examples.
#### 4. How to mock generic methods (template methods)?
Same as the Mock method of the ordinary method, just use the same generic parameters directly on the Mock method.
Just use the same generic parameters directly on the mock method.
See the use case of the `DemoTemplateTest` test class in the Java and Kotlin examples.
@ -31,7 +31,7 @@ See the use case of the `DemoTemplateTest` test class in the Java and Kotlin exa
#### 5. Why mocking methods in the `String` class in the Kotlin project does not work?
The `String` type in Kotlin language is actually `kotlin.String` instead of `java.lang.String`. However, when this type is built from bytecode, it will be replaced with Java's `java.lang.String` class, so no matter if the Mock target is written as `kotlin.String` or `java.lang.String`, it cannot match the original called method.
The `String` type in Kotlin language is actually `kotlin.String` instead of `java.lang.String`. However, when this type is built from bytecode, it will be replaced with Java's `java.lang.String` class, so no matter if the mock target is written as `kotlin.String` or `java.lang.String`, it cannot match the original called method.
In actual scenarios, there are very few scenarios where methods in the `String` class need to be mocked, so `TestableMock` has not dealt with this situation specifically.

View File

@ -4,8 +4,8 @@ Use TestableMock
`TestableMock` is an assist tool for Java unit testing based on source code and bytecode enhancement, including the following functions:
- [Access private members of the class under test](en-us/doc/private-accessor.md): enable unit tests directly invoke or access private members of the class under test, solve the problems of private member initialization and private method testing
- [Quick Mock arbitrary call](en-us/doc/use-mock.md): quickly replace any method invocation in the class under test with a mock method, solve the cumbersome use of traditional mock tools problem
- [Auxiliary test void method](en-us/doc/test-void-method.md): use the Mock validator to check the internal logic of method, solve the problem that unit testing is difficult to implement to the method with no return value
- [Quick mock arbitrary call](en-us/doc/use-mock.md): quickly replace any method invocation in the class under test with a mock method, solve the cumbersome use of traditional mock tools problem
- [Auxiliary test void method](en-us/doc/test-void-method.md): use the mock validator to check the internal logic of method, solve the problem that unit testing is difficult to implement to the method with no return value
## Use in Maven project

View File

@ -68,7 +68,7 @@ class Demo {
}
```
To test this method, you can use `TestableMock` to quickly mock out the `System.out.println` method. In the Mock method body, you can simply call the original method (equivalent to not affecting the original method function, only used for call recording), or leave it blank (equivalent to removing the side effects of the original method).
To test this method, you can use `TestableMock` to quickly mock out the `System.out.println` method. In the mock method body, you can simply call the original method (equivalent to not affecting the original method function, only used for call recording), or leave it blank (equivalent to removing the side effects of the original method).
After executing the void type method under test, use `InvokeVerifier.verify()` to verify whether the incoming print content meets expectations:

View File

@ -3,7 +3,7 @@ Self-Help Troubleshooting
Compared with `Mockito` and other mock tools where developers have to manually inject mock classes, `TestableMock` uses method name and parameter type matching to automatically find invocations that require mock. While this mechanism brings convenience, it may also cause unexpected mock replacement.
To troubleshoot mock-related issues, just add the `@MockWith` annotation to the test class, and configure the parameter `diagnose` to `MockDiagnose.ENABLE`, so the detailed Mock method replacement process will be printed when the test is run.
To troubleshoot mock-related issues, just add the `@MockWith` annotation to the test class, and configure the parameter `diagnose` to `MockDiagnose.ENABLE`, so the detailed mock method replacement process will be printed when the test is run.
```java
@MockWith(diagnose = MockDiagnose.ENABLE)

118
docs/en-us/doc/use-mock.md Normal file
View File

@ -0,0 +1,118 @@
Fast Mocking
---
Compared with the class-granularity mocking practices of existing mock tools, `TestableMock` allows developers to directly define a single method and use it for mocking. With the principle of convention over configuration, mock method replacement will automatically happen when the specified method in the test class match an invocation in the class under test.
> In summary, there are two simple rules:
> - Mock non-constructive method, copy the original method definition to the test class, add a parameter of the same type as the caller, and add a `@MockMethod` annotation
> - Mock construction method, copy the original method definition to the test class, replace the return value with the constructed type, the method name is arbitrary, and add a `@MockContructor` annotation
> **Note**: There is also a convention in the current version that the name of the test class should be `<NameOfClassUnderTest> + Test`, which is usually the by-default naming convention of Java unit tests. This constraint may be relaxed or removed in future versions of `TestableMock`.
The detail mock method definition convention is as follows:
#### 1. Mock method calls of any class
Define an ordinary method annotated with `@MockMethod` in the test class with exactly the same signature (name, parameter, and return value type) as the method to be mocked, and then add an extra parameter as the first parameter of method, with the same type as the object that the method originally belongs to.
At this time, all invocations to that original method in the class under test will be automatically replaced with invocations to the above-mentioned mock method when the unit test is running.
**Note**: When several methods to be mocked have the same name, you can put the name of the method to be mocked in the `targetMethod` parameter of `@MockMethod` annotation, so that the mock method itself can be named at will.
For example, there is a call to `"anything".substring(1, 2)` in the class under test, and we want to change it to a fixed string when running the test, we only need to define the following method in the test class:
```java
// The original method signature is `String substring(int, int)`
// The object `"anything"` that invokes this method is of type `String`
// Adds a `String` type parameter to the first position the mock method parameter list (parameter name is arbitrary)
// This parameter can be used to get the value and context of the actual invoker at runtime
@MockMethod
private String substring(String self, int i, int j) {
return "sub_string";
}
```
The following example shows the usage of the `targetMethod` parameter, and its effect is the same as the above example:
```java
// Use `targetMethod` to specify the name of the method that needs to be mocked
// The method itself can now be named arbitrarily, but the method parameters still need to follow the same matching rules
@MockMethod(targetMethod = "substring")
private String use_any_mock_method_name(String self, int i, int j) {
return "sub_string";
}
```
For complete code examples, see the `should_able_to_mock_common_method()` test cases in the `java-demo` and `kotlin-demo` sample projects. (Because Kotlin has made magical changes to the String type, the method under test in the Kotlin example adds a layer of encapsulation to the `BlackBox` class)
#### 2. Mock the member method of the class under test itself
Sometimes, when testing certain methods, it is desirable to mock out some other member methods of the class under test itself.
The solution is the same as the previous case. The first parameter type of the mock method needs to be the same as that of the class under test.
For example, there is a private method with the signature `String innerFunc(String)` in the class under test. If we want to replace it during testing, we only need to define the following method in the test class:
```java
// The type to test is `DemoMock`
// So when defining the mock method, add a parameter of type `DemoMock` to the first position of parameter list (the name is arbitrary)
@MockMethod
private String innerFunc(DemoMock self, String text) {
return "mock_" + text;
}
```
For complete code examples, see the `should_able_to_mock_member_method()` test case in the `java-demo` and `kotlin-demo` sample projects.
#### 3. Mock static methods of any class
Mock for static methods is the same as for any ordinary methods. But it should be noted that when the mock method of a static method is called, the actual value of the first parameter passed in is always `null`.
For example, if the static method `secretBox()` of the `BlackBox` type is invoked in the class under test, and the method signature is changed to `BlackBox secretBox()`, the mock method is as follows:
```java
// The target static method is defined in the `BlackBox` type
// When defining the mock method, add a parameter of type `BlackBox` to the first position parameter list (the name is arbitrary)
// This parameter is only used to identify the target type, the actual incoming value will always be `null`
@MockMethod
private BlackBox secretBox(BlackBox ignore) {
return new BlackBox("not_secret_box");
}
```
For complete code examples, see the `should_able_to_mock_static_method()` test case in the `java-demo` and `kotlin-demo` sample projects.
#### 4. Mock `new` operation of any type
Define an ordinary method annotated with `@MockContructor` in the test class, make the return value type of the method the type of the object to be created, and the method parameters are exactly the same as the constructor parameters to be mocked, the method name is arbitrary.
At this time, all operations in the class under test that use `new` to create the specified class (and use the constructor that is consistent with the mock method parameters) will be replaced with calls to the custom method.
For example, if there is a call to `new BlackBox("something")` in the class under test, and you want to change it during unit testing (usually by replacing it with a mock object, or by replacing it with a temporary object created with test parameters), just define the following mock method:
```java
// The signature of the constructor to be mocked is `BlackBox(String)`
// No need to add additional parameters to the mock method parameter list, and the name of the mock method is arbitrary
@MockContructor
private BlackBox createBlackBox(String text) {
return new BlackBox("mock_" + text);
}
```
> You can still use the `@MockMethod` annotation, and configure the `targetMethod` parameter value to `"<init>"`, and the rest is the same as above. The effect is the same as using the `@MockContructor` annotation
For complete code examples, see the `should_able_to_mock_new_object()` test case in the `java-demo` and `kotlin-demo` sample projects.
#### 5. Identify the current test case and invoke source
In the mock method, you can use `TestableTool.TEST_CASE` and `TestableTool.SOURCE_METHOD` to identify **the name of the currently running test case** and **the name of the method under test before entering the mock method**, so as to distinguish different invocation source.
> The implementation mechanism of these two fields is based on call stack analysis. Although various special cases have been dealt with, there is still the possibility of misjudgment in complex scenarios involving multiple threads. If you find a relevant reproducible BUG, please submit an issue on Github.
For complete code examples, see the `should_able_to_get_source_method_name()` and `should_able_to_get_test_case_name()` test cases in the `java-demo` and `kotlin-demo` sample projects.
#### 6. Verify the sequence and parameters of the mock method being invoked
In test cases, you can use the `TestableTool.verify()` method, and cooperate with `with()`, `withInOrder()`, `without()`, `withTimes()` and other methods to verify the mock call situation.
For details, please refer to the [Check Mock Call](en-us/doc/matcher.md) document.

View File

@ -1,2 +1,5 @@
* [首页](/zh-cn/)
* [问题和反馈](https://github.com/alibaba/testable-mock/issues)
* 语言
* [English](/en-us/)
* 中文