testable-mock/docs/en-us/doc/troubleshooting.md

92 lines
5.4 KiB
Markdown
Raw Normal View History

2020-12-23 20:19:15 +08:00
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.
2021-04-06 00:03:38 +08:00
For this reason, `TestableMock` will automatically save the mock scanning log of the last test run in the project build directory. The default location is `target/testable-agent.log` (Maven project) or `build/testable-agent.log` (Gradle project).
2020-12-23 20:19:15 +08:00
2021-04-06 00:03:38 +08:00
Examples of log content are as follows:
2020-12-23 20:19:15 +08:00
```text
2021-04-06 00:03:38 +08:00
[INFO] Start at Mon Jan 00 00:00:00 CST 0000
... ...
[INFO] Found test class com/alibaba/testable/demo/basic/DemoMockTest
[INFO] Found 6 test cases
[INFO] Found mock class com/alibaba/testable/demo/basic/DemoMockTest$Mock
[INFO] Found 8 mock methods
[INFO] Found source class com/alibaba/testable/demo/basic/DemoMock
[INFO] Found method <init>
[INFO] Found method newFunc
[INFO] Line 19, mock method "createBlackBox" used
[INFO] Found method outerFunc
[INFO] Line 27, mock method "innerFunc" used
[INFO] Line 27, mock method "staticFunc" used
[INFO] Found method commonFunc
[INFO] Line 34, mock method "trim" used
[INFO] Line 34, mock method "sub" used
[INFO] Line 34, mock method "startsWith" used
... ...
2021-04-06 00:03:38 +08:00
[INFO] Completed at Mon Jan 00 00:00:00 CST 0000
2020-12-23 20:19:15 +08:00
```
The log shows all the mocked invocation and corresponding code line numbers in the class under test.
2021-02-02 14:24:12 +08:00
2021-04-06 00:03:38 +08:00
According to the targeted test classes, below are some simple clues for self-troubleshooting. Suppose the class under test is "com.demo.BizService", the test class is "com.demo.BizServiceTest", and the mock container class is "com.demo.BizServiceTest.Mock":
2021-04-06 00:03:38 +08:00
- If the log file is no generated, please check whether the `pom.xml` or `build.gradle` configuration correctly introduces `TestableMock` dependencies
- If only `com/demo/BizServiceTest$Mock` is found in the output, please check whether the mock class is created at correct place
- If both the test class and the mock class are found, but the class under test `com/demo/BizService` not appeared, please check whether the test class is in the same package of the class under test, and the name is "<ClassUnderTest>+Test", otherwise `@MockWith` annotation should be used
- If all the three classes are found, and `Found method xxx` are output, but there is no mock replacement happen at the expected code line, please check whether the mock method definition matches the target method
2021-04-06 00:03:38 +08:00
For situations where expected mocking is not take effect, you could add a `@MockDiagnose` annotation to the mock class, and set the diagnosis level to `LogLevel.VERBOSE` for further investigation information.
```java
2021-04-06 00:03:38 +08:00
class BizServiceTest {
@MockDiagnose(LogLevel.VERBOSE)
public static class Mock {
...
}
}
```
2021-03-03 09:46:21 +08:00
Executing the unit test again will print out the signatures of all mock methods, and the signatures of all invocations scanned in the class under test:
```text
2021-04-06 00:03:38 +08:00
[INFO] Found test class com/alibaba/testable/demo/basic/DemoMockTest
[TIP] Test case "should_mock_new_object"
2021-03-02 23:42:04 +08:00
... ...
2021-04-06 00:03:38 +08:00
[TIP] Test case "should_set_mock_context"
[INFO] Found 6 test cases
[INFO] Found mock class com/alibaba/testable/demo/basic/DemoMockTest$Mock
[TIP] Mock constructor "createBlackBox" as "com.alibaba.demo.basic.model.mock.BlackBox(java.lang.String)"
[TIP] Mock method "innerFunc" as "com.alibaba.demo.basic.DemoMock::innerFunc(java.lang.String) : java.lang.String"
2021-03-02 23:42:04 +08:00
... ...
2021-04-06 00:03:38 +08:00
[TIP] Mock method "callFromDifferentMethod" as "()Ljava/lang/String;"
[INFO] Found 8 mock methods
[INFO] Found source class com/alibaba/testable/demo/basic/DemoMock
[INFO] Found method <init>
[TIP] Line 13, constructing "java.lang.Object()"
[INFO] Found method newFunc
[TIP] Line 19, constructing "com.alibaba.demo.basic.model.mock.BlackBox(java.lang.String)"
[INFO] Line 19, mock method "createBlackBox" used
[TIP] Line 19, invoking "com.alibaba.demo.basic.DemoMockTest$Mock::createBlackBox(java.lang.String) : com.alibaba.demo.basic.model.mock.BlackBox"
[TIP] Line 20, invoking "com.alibaba.demo.basic.model.mock.BlackBox::get() : java.lang.String"
[INFO] Found method outerFunc
[TIP] Line 27, constructing "java.lang.StringBuilder()"
[TIP] Line 27, invoking "java.lang.StringBuilder::append(java.lang.String) : java.lang.StringBuilder"
[TIP] Line 27, invoking "com.alibaba.demo.basic.DemoMock::innerFunc(java.lang.String) : java.lang.String"
[INFO] Line 27, mock method "innerFunc" used
... ...
```
The logs are formatted in follow pattern:
- `Mock constructor "<MockMethodName>" as "<Signature>" for "<TypeName>"` Mock constructor found in test class
- `Mock method "<MockMethodName>" as "<Signature>"` Mock method found in test class (the first parameter that identify the mock target class is currently kept)
- `Line XX, constructing "<TypeName>" as "<Signature>"` Constructor invocation found in test under class
- `Line XX, invoking "<MethodName>" as "<Signature>"` Member method invocation found in test under class
2021-04-06 00:03:38 +08:00
> In order to clearly distinguish between the type of method return value and the type of invoker, the method signature recorded in the log uses a method definition structure similar to `Kotlin`.
Comparing the actual signature of the original call with the signature defined by the mock method, the problem is usually found quickly.