Compare commits

...

247 Commits

Author SHA1 Message Date
金戟
30570ae69d fix: verifier should compare arrays in deep 2023-05-17 19:08:42 +08:00
金戟
320ee632b7 test: add cases of collection tool methods 2022-12-17 08:12:54 +08:00
金戟
ba284f6518 doc: introduce CollectionTool class 2022-12-16 23:09:19 +08:00
金戟
c6e861e5cf refactor: move fastListOf method out of CollectionTool 2022-12-15 09:42:02 +08:00
金戟
0287d27d85 release v0.7.9 2022-12-14 19:25:55 +08:00
金戟
1e9079e8d3 feat: move collection creation methods to CollectionTool 2022-12-14 00:34:03 +08:00
金戟
e7a2b06698 feat: generate none-null object for classes not in jvm package 2022-12-13 23:30:47 +08:00
金戟
ab87ef1fd0 feat: cache constructor parameter types for efficiency 2022-12-12 08:20:58 +08:00
金戟
d5c1f780de feat: invoke super constructor explicitly in generated class 2022-12-11 20:06:46 +08:00
金戟
a463bcbfd9 fix: correctly handle array type 2022-12-11 12:03:37 +08:00
金戟
c53f1e01f0 feat: find best constructor of super class 2022-12-11 08:10:46 +08:00
金戟
12989aa612 refactor: merge UNREACHABLE_CLASSES and PRELOADED_CLASSES 2022-12-10 12:22:37 +08:00
金戟
61a3090431 refactor: update junit version 2022-12-09 22:09:12 +08:00
金戟
e9ce61d83c doc: fix test case name 2022-12-06 11:59:57 +08:00
金戟
d9f65189f7 feat: add RICH_INTERFACE option to avoid introduce omni class in system interface implementation 2022-12-04 17:52:19 +08:00
金戟
1446382f53 feat: handle many special cases of system class creation 2022-12-04 07:34:42 +08:00
金戟
ada70f88c0 feat: get generic type mapping recursively 2022-12-03 17:15:18 +08:00
金戟
65b58d0861 feat: avoid duplicate method declaration 2022-12-02 23:17:13 +08:00
金戟
a67dd7b73f feat: add targetClassName parameter to mock invoke annotation 2022-12-01 23:41:41 +08:00
金戟
1f6fc2e4bc feat: support generate system interface class 2022-12-01 00:32:21 +08:00
金戟
eb8ccb0a40 feat: choose correct constructor for system preloaded classes 2022-11-30 00:02:42 +08:00
金戟
dcbb305e10 fix: incorrect onmi constructor option judgement 2022-11-27 21:13:05 +08:00
金戟
8c0a74264a refactor: move string util methods to core package 2022-11-27 21:10:53 +08:00
金戟
dcc5108149 fix: look for outer mock class failed 2022-11-26 22:05:24 +08:00
金戟
0a40e07739 feat: upgrade transmittable-thread-local to 2.14.2 2022-11-26 22:04:53 +08:00
金戟
9e5f722076 fix: duplicate naming 2022-11-25 23:05:49 +08:00
金戟
1dcbe6b0f2 feat: get rid of Pair class 2022-11-25 15:00:04 +08:00
金戟
e4ff8ce57e fix: typo and condition in comment 2022-11-24 22:13:06 +08:00
金戟
47871d0eb6 feat: always consider class with MockContainer annotation as mock class 2022-11-23 14:05:10 +08:00
金戟
e52538acf3 feat: parse mock class considering MockContainer annotation 2022-11-21 00:41:27 +08:00
金戟
db91a0ea34 feat: transform mock class according to MockContainer annotation 2022-11-20 20:11:46 +08:00
金戟
d912e53ebc feat: implement EXCEPT_INTERFACE option of omni constructor 2022-11-20 13:09:04 +08:00
金戟
1e2e1e6d84 doc: update test case name 2022-11-20 00:05:52 +08:00
金戟
1bb6007eb5 test: also verify mock invocation times 2022-11-20 00:01:24 +08:00
金戟
6632fae529 feat: add testcase for inherited mock container 2022-11-19 23:32:06 +08:00
金戟
9018301bfc feat: add MockContainer annotation 2022-11-19 22:28:28 +08:00
金戟
dbaeb3bcf1 doc: should do both push and push tag 2022-11-17 21:05:15 +08:00
金戟
fc7e4af2c6 feat: support generate class with inherited genericity 2022-11-14 20:36:44 +08:00
金戟
76cff45123 feat: support generate class with dollar in name 2022-11-14 20:36:37 +08:00
金戟
5c8ef00fce feat: support generate parameterized class 2022-11-14 20:36:29 +08:00
金戟
f8501b0722 fix: generate correct type name 2022-11-14 22:40:34 +08:00
金戟
46e4499035 release v0.7.8 2022-11-13 20:13:40 +08:00
金戟
f508f7aba9 refactor: always use the collection method in core module 2022-11-13 18:15:42 +08:00
金戟
6e029f61d8 feat: add util method for quick create set 2022-11-01 16:35:47 +08:00
金戟
b654a3cfaa feat: support generate method with template types 2022-10-09 20:31:13 +08:00
金戟
038ae8dba0 feat: support construct simple interface and abstract class 2022-10-08 20:20:18 +08:00
金戟
11a5565cee feat: use same package path of parent to avoid access error 2022-10-08 11:30:43 +08:00
金戟
ba77a0138c fix: let the kotlin testcases pass with 'mvn test' locally 2022-09-29 17:22:35 +08:00
金戟
9788dd9ecc feat: add common used collection creation function to library 2022-08-09 14:25:52 +08:00
金戟
55a6e141fc doc: update faq to fit current mock inovke annotation parameter 2022-06-11 22:48:26 +08:00
金戟
81a2817b6c fix: fit for jvm 1.6 2022-06-04 23:23:59 +08:00
金戟
ef6099a63d feat: generate empty sub class for interface 2022-06-04 23:11:12 +08:00
金戟
3c11676408 feat: add original InMemoryJavaCompiler 2022-06-03 13:29:25 +08:00
金戟
b2a87bffbe refactor: use constant dollar symbol 2022-05-29 14:08:35 +08:00
金戟
1a2083416e doc: describe the MockContext fields 2022-05-29 11:35:23 +08:00
金戟
c1e6d00953 doc: one more thing to mention 2022-05-28 17:39:35 +08:00
金戟
39b742b290 release v0.7.7 2022-05-28 13:34:27 +08:00
金戟
0a5666c0be fix: only generate named lambda method for mocked ones 2022-05-28 13:26:37 +08:00
金戟
006e742c28 fix: upgrade asm to support java 17 2022-05-19 19:00:59 +08:00
金戟
237b9ebb15 doc: fix link to invoke matcher page 2022-05-19 18:53:13 +08:00
金戟
7aedcf63b5 release v0.7.6 2022-04-22 17:14:33 +08:00
金戟
0f64d52718 feat: should skip mockito generated class 2022-04-22 17:09:56 +08:00
金戟
4ed1323a62 feat: package mapping map shuold be ordered 2022-04-22 16:38:26 +08:00
Fan Lin
ae1ba8b4ff
Merge pull request #274 from zcbbpo/ISSUES-272
Fixed java9+ String makeConcatWithConstants not work for method refer…
2022-04-01 17:01:30 +08:00
zcbbpo
00f25d3622 Fixed java9+ String makeConcatWithConstants not work for method reference 2022-04-01 11:14:49 +08:00
金戟
2e58ae8360 release v0.7.5 2022-03-08 12:38:35 +08:00
金戟
ff54c57608 fix: should handle array type method properly 2022-03-08 12:35:18 +08:00
金戟
351b3399e6 feat: elastic plugin class should contain only one constructor 2022-02-20 22:22:00 +08:00
金戟
df9e2395cc doc: describe no unique public constructor error 2022-02-20 22:09:45 +08:00
金戟
b9064d3d47 doc: intellij plugin usage english edition 2022-02-05 22:52:48 +08:00
金戟
c967456569 doc: add intellij plugin usage 2022-02-05 21:28:28 +08:00
金戟
692b4435aa release v0.7.4 2022-02-02 21:02:28 +08:00
金戟
6379f16266 fix #261, java.net.URL is loaded before OmniClassHandler 2022-02-02 21:02:28 +08:00
Fan Lin
63a6a9fdca
Merge pull request #259 from oldratlee/upgrade-ttl
upgrade TTL to 2.12.4, fix ClassCircularityError
2022-01-12 10:05:23 +08:00
Jerry Lee
7e24503611 upgrade TTL to 2.12.4, fix ClassCircularityError
more discussion see
https://github.com/alibaba/transmittable-thread-local/issues/278
2022-01-12 00:43:02 +08:00
金戟
3120eba3af update release note 2022-01-10 20:55:39 +08:00
金戟
02f15177fc release v0.7.3 2022-01-09 22:45:14 +08:00
Fan Lin
a25f14c0ec
Merge pull request #257 from zcbbpo/FIXED-INVOKEINTERFACE_1
Fixed invokeinterface issuse
2022-01-07 14:55:25 +08:00
jimcao
635cbf62fb completed 2022-01-06 15:13:32 +08:00
jimcao
17b31b39dd refine code 2022-01-06 13:13:09 +08:00
jimcao
0d43d93a29 temp update 2022-01-06 11:52:18 +08:00
jimcao
66db3cff7d temp 2022-01-05 09:49:49 +08:00
jimcao
3343a26de8 Add interface static test case 2022-01-05 09:12:38 +08:00
jimcao
de2e520d95 Fixed interface default method 2022-01-04 18:02:49 +08:00
金戟
59bcbfdf37 release v0.7.2 2021-12-17 14:39:20 +08:00
Fan Lin
cdad0d2446
Merge pull request #251 from zcbbpo/Fxied-static-instance-reference-issue
fixed static instance reference issue
2021-12-17 13:40:45 +08:00
jimcao
ba5102ffd9 fixed static instance reference issue 2021-12-16 17:26:38 +08:00
金戟
db4e02a201 release v0.7.1 2021-12-11 22:59:49 +08:00
金戟
fda7ee23c7 fix #248, should not look up package mapping if found mock class 2021-12-11 14:40:27 +08:00
金戟
140e54983b release v0.7.0 2021-11-07 11:07:39 +08:00
金戟
548d7ba21f add upgrade guide for 0.7.0 2021-11-07 11:06:37 +08:00
金戟
c2d456da97 use MockInvoke and MockNew 2021-11-03 11:44:44 +08:00
金戟
28500558fc rename verify() to verifyInvoked(), avoid name conflict with system method 2021-11-02 23:39:48 +08:00
金戟
990f407ebe should throw NullPointerException when invoke mock method on null object (issue-163) 2021-11-02 23:09:57 +08:00
金戟
f6206ee294 add release note of 0.6.10 2021-10-31 23:36:32 +08:00
金戟
8cfba333ff release v0.6.10 2021-10-31 14:24:10 +08:00
Fan Lin
397fc3d2fa
Merge pull request #234 from zcbbpo/FIXED-LAMBDA-MR
[Lambda] Fixed method reference external var
2021-10-31 14:19:02 +08:00
jim cao
b7a076dfaf fixed external var 2021-10-30 19:40:21 +08:00
金戟
aee2ec2767 fix typo and format code 2021-10-27 07:33:08 +08:00
Fan Lin
682d822249
Merge pull request #231 from HankDevelop/0.6
接口继承支持
2021-10-27 07:27:46 +08:00
Fan Lin
6cf3f993ca
Merge branch 'master' into 0.6 2021-10-27 07:27:23 +08:00
HankDevelop
0cce5a6ec0 接口继承支持 2021-10-26 19:57:10 +08:00
金戟
0917406c44 release v0.6.9 2021-10-17 22:56:33 +08:00
金戟
3bf19ee6d0 fix NullPointerException when passing null as parameter of private accessor 2021-10-17 22:56:33 +08:00
Fan Lin
e1afb1cd54
Merge pull request #223 from Augustine-C/fix_flaky
Fixed a flaky test in core.tool.OmniAccessorTest
2021-09-30 10:47:59 +08:00
Augustine Cui
10953ff02a Fixed a flaky test in core.tool.OmniAccessorTest
This test is flaky since the method `java.lang.Class.getDeclaredFields` is non-deterministic, and `GetDeclaredFilelds`  is ultimately used in the `com.alibaba.testable.core.util.TypeUtil.getAllFields`
I converted the result to a `HashSet` to avoid ordering issues, so the specific ordering of the fields would not affect the result. I think this change can prevent test failure due to future change in the JVM.
2021-09-29 17:10:37 -07:00
金戟
80b0f3b878 do not introduce sun package dependence 2021-09-28 21:26:16 +08:00
Fan Lin
8fbd459280
Merge pull request #208 from zcbbpo/FIXED-LAMBDA-METHOD-REFERENCE-ISSUES
Fixed method reference
2021-09-28 20:46:51 +08:00
jimcao
f3309f933e fixed method reference 2021-09-24 15:20:13 +08:00
金戟
b47204e329 hold images in cdn 2021-09-15 21:11:29 +08:00
金戟
6616ff1174 add description about modify static final member 2021-08-09 08:56:40 +08:00
金戟
09ecd0d7c0 release v0.6.8 2021-08-08 21:53:34 +08:00
金戟
93db467f43 update maintain plan 2021-08-08 21:33:58 +08:00
金戟
a78931ae81 allow modify static final field 2021-07-14 21:29:32 +08:00
金戟
93ad1fa94f allow to dump single mock class 2021-07-12 21:41:31 +08:00
金戟
2780ccc6fa for better performance 2021-07-12 20:37:13 +08:00
金戟
fd3b088f59 release v0.6.7 2021-06-11 17:36:43 +08:00
金戟
e812aa6126 fix stack effect value of xaload opcode 2021-06-11 17:25:38 +08:00
金戟
b949f57d54 in favor of static import 2021-06-06 23:04:42 +08:00
金戟
0551240c7d fix incorrect class name in mock target checking log 2021-06-01 19:40:22 +08:00
金戟
8a3a0cf6bf add with thread pool doc 2021-06-01 10:58:00 +08:00
金戟
d3ab246c78 should travel parent classes 2021-05-31 23:36:53 +08:00
金戟
142b0e5a1e update doc for v0.6.6 2021-05-27 19:03:11 +08:00
金戟
38221a67ef release 0.6.6 2021-05-22 19:00:35 +08:00
金戟
993c178adf fit mock target checking for kotlin 2021-05-22 18:31:03 +08:00
金戟
3786c6251e always transform all test classes 2021-05-22 18:12:26 +08:00
金戟
e5f8e5244c construct void object is unnecessary 2021-05-22 16:36:06 +08:00
金戟
e13dce7ac6 prefer to use minimal exception count 2021-05-22 11:12:58 +08:00
金戟
3265803dec expose constructor of void class 2021-05-22 01:27:12 +08:00
金戟
ef3891bd57 add release note 2021-05-22 01:24:40 +08:00
金戟
fcbdb7275b add test case of basic type constructing 2021-05-21 00:25:02 +08:00
金戟
ea4c6c5b3e allow disable mock target checking 2021-05-16 23:16:51 +08:00
金戟
381ff52515 also check methods from parent classes 2021-05-15 16:16:01 +08:00
金戟
c5f39dfae3 refactor logs, print mock method information in mock class handler 2021-05-15 15:57:02 +08:00
金戟
7f8ef70e57 move byte code logic to util class 2021-05-15 15:20:16 +08:00
金戟
23af64475a support target exist checking of mock method 2021-05-15 11:04:45 +08:00
金戟
7181b49211 package prefix should end with a slash 2021-05-14 21:24:34 +08:00
金戟
cd7b9cc922 allow disable mocking 2021-05-11 22:42:31 +08:00
金戟
46288fa0e9 add detail release plan 2021-05-05 23:23:11 +08:00
金戟
e61597ba8b add package mapping doc 2021-05-04 13:22:07 +08:00
金戟
c577301493 support mock package mapping 2021-05-03 14:56:33 +08:00
金戟
a33908db41 support absolute config path and update docs 2021-05-03 11:39:21 +08:00
金戟
4ea97fe13f always print out context path of testable agent 2021-05-03 10:56:36 +08:00
金戟
7cda8ffd36 add plan for mybatis mock function 2021-05-03 10:37:33 +08:00
金戟
1da98a0364 small fix for android demo 2021-05-03 09:30:23 +08:00
金戟
c6d892da2d global exclude robolectric package from omni processor 2021-05-02 20:11:55 +08:00
金戟
d1f2c3da97 add a mini android demo 2021-05-02 20:10:07 +08:00
金戟
f40cfe929a always static import asserts 2021-05-02 09:25:36 +08:00
金戟
96d1f9d633 release v0.6.5 2021-05-02 08:10:58 +08:00
金戟
350802fc9b fix mock method in super class ignored in association scope 2021-05-01 19:28:26 +08:00
金戟
0ae5163435 revert test code 2021-05-01 17:31:13 +08:00
金戟
0e581a7eeb add kotlin demo for mock scope 2021-05-01 17:25:48 +08:00
金戟
b68ff99800 rename construction options 2021-05-01 16:58:02 +08:00
金戟
7754f828cc fix issue of invoking method with single array parameter 2021-05-01 16:05:42 +08:00
金戟
3d62c91291 association check require at least 6 stack space 2021-04-29 13:23:19 +08:00
金戟
14c3d841c5 add demo for test scope 2021-04-28 23:52:52 +08:00
金戟
5f6cf3888c static final field is not assignable during runtime 2021-04-26 08:30:57 +08:00
金戟
75c6a67b8f support construction options 2021-04-25 23:27:51 +08:00
金戟
d11402dd6c update description of pkgPrefix 2021-04-25 18:25:20 +08:00
金戟
db771b9c66 fix an omni constructor issue caused by array-in-array type 2021-04-25 18:24:13 +08:00
金戟
338c7828c8 skip jacoco generated members and do not travel array of basic classes 2021-04-24 23:30:48 +08:00
金戟
8ebe2a5d0c allow constructor with parameter of same type as class under constructing 2021-04-24 18:46:04 +08:00
金戟
4f3e3f0093 throw with information about the class failed to construct 2021-04-24 18:14:53 +08:00
金戟
9924d7d2fc release v0.6.4 2021-04-24 17:43:43 +08:00
金戟
9f5867ed76 support nested annotation of junit 5 2021-04-24 16:59:29 +08:00
金戟
be0a580a04 AbstractCollection is unranchable in java agent 2021-04-24 16:23:01 +08:00
金戟
78d7ee21a6 use void type instead of null type 2021-04-24 11:47:41 +08:00
金戟
af409a65a8 fix circle check rounded by getType not equals with getClass 2021-04-23 21:41:30 +08:00
金戟
a67619d574 add verbose log for omni constructor 2021-04-23 20:34:15 +08:00
金戟
b89daa22c3 always skip null element when traveling class 2021-04-23 19:30:54 +08:00
金戟
e948e625ea better to skip classes in javax/crypto package 2021-04-21 16:32:00 +08:00
金戟
d463f863db local variable table of non-static method can be empty 2021-04-20 21:17:09 +08:00
金戟
31140bef87 add description of global properties configurations 2021-04-18 15:06:36 +08:00
金戟
d2944a88fb reorder parameters 2021-04-18 13:37:36 +08:00
金戟
9d6e4dd1fa bump to v0.6.3 2021-04-18 10:26:06 +08:00
金戟
9c09bf9653 avoid to select constructor with parameter of its own type 2021-04-18 09:45:57 +08:00
金戟
6d87653fa2 handle non-static method without this reference 2021-04-18 09:15:03 +08:00
金戟
eec88f4bd9 should convert package prefix to slash separated format 2021-04-17 19:52:32 +08:00
金戟
5921ccab07 allow skip specified class from omni enhancer 2021-04-17 19:24:02 +08:00
金戟
8dde402a8c get resource could be null 2021-04-17 18:45:29 +08:00
金戟
d10478f95f package prefix should auto append dot 2021-04-17 17:46:35 +08:00
金戟
0c063e9b1f support custom inner mock class name 2021-04-17 17:16:02 +08:00
金戟
b8771f0dac simplify premain logic 2021-04-16 12:52:24 +08:00
金戟
42dd58584b mark date as basic type 2021-04-14 09:28:07 +08:00
金戟
ce55bb4c9a skip all configuration class for omni handler 2021-04-12 16:40:53 +08:00
金戟
cff2d1ae5a fix release script 2021-04-09 14:25:02 +08:00
金戟
5904ad99cb release v0.6.2 2021-04-07 21:38:24 +08:00
金戟
74fbc5b53f support configure file 2021-04-07 09:40:20 +08:00
金戟
f6b5bab250 manual generated serialVersionUID not works 2021-04-07 00:05:29 +08:00
金戟
f2feb3cc68 more precise omni handler filter 2021-04-06 23:08:30 +08:00
金戟
b41923bfa0 release v0.6.1 2021-04-06 08:09:23 +08:00
金戟
7c1f18de46 optimize docs 2021-04-06 00:03:38 +08:00
金戟
c393d40d0d better log description, handling -> found 2021-04-05 15:52:12 +08:00
金戟
d4a69528a7 use relative path for bytecode dumping 2021-04-05 14:58:29 +08:00
金戟
a46e73a421 support specify log file path 2021-04-05 14:09:44 +08:00
金戟
01e9890234 always generate log file 2021-04-05 11:56:06 +08:00
金戟
93cdef1d6c remove gradle settings in kotlin demo 2021-04-04 15:38:43 +08:00
金戟
e2e986e50d add a tiny demo for spock 2021-04-04 15:31:18 +08:00
金戟
f5475aa18e simplify log level config 2021-04-04 00:10:56 +08:00
金戟
844323af3a fix compatibility with spring boot 2021-04-03 23:54:01 +08:00
金戟
cc2deeff1c ClassCircularityError is not an exception 2021-04-03 23:35:22 +08:00
金戟
14e4d2db5b ignore cglib classes 2021-04-03 22:51:28 +08:00
金戟
c9c8ba6c24 junit test class can also has parent 2021-04-03 22:10:18 +08:00
金戟
b5c0afb3da ignore any exception when try load class 2021-04-03 18:17:11 +08:00
金戟
617d372545 avoid to transfer gradle TestWorker class 2021-04-03 18:16:36 +08:00
金戟
58da25de53 add mock verifier support spock 2021-04-03 13:41:51 +08:00
金戟
46706ba56c add supported test framwork 2021-04-03 10:02:03 +08:00
金戟
1ced04bf29 fix loging 2021-04-02 23:50:39 +08:00
金戟
7b2f967626 add tool scripts 2021-04-01 09:22:28 +08:00
金戟
e0a4a39d55 move dump method to util package 2021-03-31 10:34:45 +08:00
金戟
b4da23a90e adopt for groovy bytecode 2021-03-31 10:34:19 +08:00
金戟
c1659242b6 fix markdown format 2021-03-28 15:10:52 +08:00
金戟
929abffb66 add english doc for omni methods 2021-03-28 14:47:00 +08:00
金戟
e370114b01 release v0.6 2021-03-27 20:05:21 +08:00
金戟
26d3178840 support set dump path for single class 2021-03-27 00:31:02 +08:00
金戟
55ccc385d5 remove unnecessary mock class reference in test class handler 2021-03-26 22:26:12 +08:00
金戟
20b346ed34 remove diagnose parameter in MockWith annotation 2021-03-26 20:20:45 +08:00
金戟
00055a4626 always print more error information 2021-03-26 01:12:52 +08:00
金戟
27174afa93 implement fall-fast anti-refactor machenism 2021-03-26 01:12:30 +08:00
金戟
3d6d3c9dd1 skip $jacocoData field 2021-03-25 13:10:49 +08:00
金戟
df7e641a0c update doc to fit version 0.6 2021-03-24 23:51:19 +08:00
金戟
3acf341d1f add kotlin test case for omni 2021-03-24 13:23:02 +08:00
金戟
52878364ee don't travel into basic class 2021-03-24 13:17:15 +08:00
金戟
9871a96db0 create omni constructor correctly 2021-03-24 00:34:17 +08:00
金戟
9b56e3d64a fit common collection interfaces 2021-03-23 21:29:54 +08:00
金戟
ea8f305152 handle circle reference 2021-03-23 00:00:48 +08:00
金戟
3feba7fdfa allow non-public mock class 2021-03-22 14:57:59 +08:00
金戟
9064f7a582 better demo for omni methods 2021-03-22 00:41:19 +08:00
金戟
b062dbc592 move private accessor to tool package 2021-03-21 07:43:22 +08:00
金戟
a623bd0a33 Merge branch 'master' into 0.6
* master:
  update faq about how to mock inner class
2021-03-20 20:25:10 +08:00
金戟
a54bb33c09 support quick create array instance 2021-03-20 20:23:23 +08:00
金戟
bbc41f2987 fix omni get path with index 2021-03-20 18:02:01 +08:00
金戟
7b9a0964bc use k8s-like model for omni demos 2021-03-20 17:30:10 +08:00
金戟
a0dae0dfe1 support wildcard match 2021-03-20 14:34:19 +08:00
金戟
f54a6ce022 handle array in query path correctly 2021-03-20 00:50:30 +08:00
金戟
606760d632 refactor test code, and omni constructor test 2021-03-18 23:51:06 +08:00
金戟
206fc5486e support access array element by index 2021-03-18 00:15:01 +08:00
金戟
af3af6b272 handle array and primary types 2021-03-17 19:26:50 +08:00
金戟
fe7420c99a implement basic omni instance construction 2021-03-17 16:24:20 +08:00
金戟
7857782125 do omni transform 2021-03-17 14:24:16 +08:00
金戟
f776deff0e update faq about how to mock inner class 2021-03-16 22:19:16 +08:00
金戟
328296ae3a complete get and set by path of common class 2021-03-16 14:31:37 +08:00
金戟
a5038320b4 convert query path to match pattern 2021-03-16 11:50:22 +08:00
金戟
bdd16c0948 generate member index of specified class 2021-03-15 23:51:21 +08:00
金戟
dce1accafb fix class reference of frame full operation 2021-03-15 19:14:26 +08:00
Fan Lin
2865093fef
Merge pull request #116 from mikero8/fix-readme
Update README_EN.md
2021-03-14 17:02:18 +08:00
Mikero
5f69b21532
Update README_EN.md
Fix an issue in English README
2021-03-13 09:14:41 -08:00
283 changed files with 10546 additions and 2049 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# maven ignore # maven ignore
target/ target/
.mvn/
# gradle ignore # gradle ignore
build/ build/

View File

@ -2,26 +2,22 @@
换种思路写Mock让单元测试更简单。 换种思路写Mock让单元测试更简单。
无需初始化不挑服务框架甭管要换的是私有方法、静态方法、构造方法还是其他任何类的任何方法也甭管要换的对象是怎么创建的。写好Mock定义加个`@MockMethod`注解,一切统统搞定。 无需初始化不挑服务框架甭管要换的是私有方法、静态方法、构造方法还是其他任何类的任何方法也甭管要换的对象是怎么创建的。写好Mock定义加个`@MockInvoke`注解,一切统统搞定。
- 文档https://alibaba.github.io/testable-mock/ - 文档https://alibaba.github.io/testable-mock/
- 国内文档镜像http://freyrlin.gitee.io/testable-mock/ - 国内文档镜像http://freyrlin.gitee.io/testable-mock/
阅读[这里](https://mp.weixin.qq.com/s/KyU6Eu7mDkZU8FspfSqfMw)了解更多故事。 阅读[这里](https://mp.weixin.qq.com/s/KyU6Eu7mDkZU8FspfSqfMw)了解更多故事。
<font size="5">**0.5版本已发布**</font>,从`0.4.x`升级到`0.5.x`版本请参考[0.5版本升级指南](https://alibaba.github.io/testable-mock/#/zh-cn/doc/upgrade-to-v05) <font size="5">**0.7版本已发布**</font>,从`0.6.x`升级到`0.7.x`版本请参考[版本升级指南](https://alibaba.github.io/testable-mock/#/zh-cn/doc/upgrade-guide)
如果有遇到其他任何使用问题和建议,请直接在[Issue](https://github.com/alibaba/testable-mock/issues)中提出,也可通过[Pull Request](https://github.com/alibaba/testable-mock/pulls)提交您的代码我们将在24小时内回复并处理
----- -----
## 版本计划 ## 项目维护说明
`TestableMock`正在持续迭代演进,以下版本计划可能在开发过程中发生调整 由于当前并行项目较多,此项目暂时转入维护阶段,在此期间`TestableMock`会继续提供不定期的版本更新。
- `0.5` 当前版本,进行中的工作内容参考[Issue](https://github.com/alibaba/testable-mock/issues)清单 如果有遇到其他任何使用问题和建议,请直接在[Issues](https://github.com/alibaba/testable-mock/issues)中提出,也可通过[Pull Request](https://github.com/alibaba/testable-mock/pulls)提交您的代码,我们将尽快回复并处理。
- `0.6` 实现第四项单元测试增强能力"[快速入参构造器](https://alibaba.github.io/testable-mock/#/zh-cn/doc/parameter-constructor)"
- `1.0` 功能稳定,一个崭新的开始
## 目录结构 ## 目录结构
@ -32,9 +28,12 @@
|-- testable-agent ➜ JavaAgent模块提供Mock测试相关功能 |-- testable-agent ➜ JavaAgent模块提供Mock测试相关功能
|-- testable-core ➜ 基础功能模块提供Mock相关注解和工具类 |-- testable-core ➜ 基础功能模块提供Mock相关注解和工具类
|-- testable-maven-plugin ➜ Maven插件模块用于简化JavaAgent注入 |-- testable-maven-plugin ➜ Maven插件模块用于简化JavaAgent注入
|-- tool ➜ 项目开发过程中的工具脚本
|-- demo |-- demo
| |-- java-demo ➜ Java语言的示例代码 | |-- java-demo ➜ Java语言的示例代码
| `-- kotlin-demo ➜ Kotlin语言的示例代码 | |-- kotlin-demo ➜ Kotlin语言的示例代码
| |-- android-demo ➜ Android项目的示例代码
| `-- spock-demo ➜ Spock测试框架的示例代码
`-- docs ➜ 项目使用文档 `-- docs ➜ 项目使用文档
``` ```

View File

@ -3,17 +3,13 @@
Write mock faster, make unit testing easier. Write mock faster, make unit testing easier.
Any test framework, no initialization, no matter private method, static method, construction method, or any other method of any class, and no matter how the object created. Any test framework, no initialization, no matter private method, static method, construction method, or any other method of any class, and no matter how the object created.
Write a mock method, add an `@MockMethod` annotation, everything is done. Write a mock method, add an `@MockInvoke` annotation, everything is done.
Usage Document: https://alibaba.github.io/testable-mock/#/en-us/ Usage Document: https://alibaba.github.io/testable-mock/#/en-us/
## Loadmap ## Roadmap
`TestableMock` is still under heavy development, the following version plans may be adjusted during the iteration `TestableMock` is still under heavy development, if you get sucked somehow, just go ahead raise an [issue](https://github.com/alibaba/testable-mock/issues) for it.
- `v0.5` it's the current version, refer to the [issue](https://github.com/alibaba/testable-mock/issues) list for the work in progress
- `v0.6` implement the functionality of "parameter constructor"
- `v1.0` all functions are stable, a brand-new start
## Directory Structure ## Directory Structure
@ -24,9 +20,12 @@ Usage Document: https://alibaba.github.io/testable-mock/#/en-us/
|-- testable-agent ➜ JavaAgent module, provides test mocking related 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 |-- testable-maven-plugin ➜ Maven plugin module, for simplify JavaAgent injection
|-- tool ➜ Scripts for project maintain
|-- demo |-- demo
| |-- java-demo ➜ Java code example | |-- java-demo ➜ Java code example
| `-- kotlin-demo ➜ Kotlin code example | |-- kotlin-demo ➜ Kotlin code example
| |-- android-demo ➜ Android app code example
| `-- spock-demo ➜ Spock framwork code example
`-- docs ➜ Source code of usage document `-- docs ➜ Source code of usage document
``` ```

15
demo/android-demo/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

1
demo/android-demo/app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,55 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.alibaba.testable.demo"
minSdkVersion 30
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
testOptions {
unitTests {
includeAndroidResources = true
all {
jvmArgs "-javaagent:${classpath.find { it.name.contains("testable-agent") }.absolutePath}"
}
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.appcompat:appcompat:1.3.0-rc01'
implementation 'com.google.android.material:material:1.1.0'
testImplementation 'androidx.test:core:1.4.0-alpha05'
testImplementation 'androidx.test:runner:1.4.0-alpha05'
testImplementation 'junit:junit:4.+'
testImplementation 'org.robolectric:robolectric:4.5.1'
testImplementation 'com.alibaba.testable:testable-all:0.7.9'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,24 @@
package com.alibaba.testable.demo
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.alibaba.testable.demo", appContext.packageName)
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alibaba.testable.demo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestableAndroidDemo" />
</manifest>

View File

@ -0,0 +1,63 @@
package com.alibaba.testable.demo;
import com.alibaba.testable.demo.model.BlackBox;
/**
* 演示基本的Mock功能
* Demonstrate basic mock functionality
*/
public class DemoBasic {
/**
* method with new operation
*/
public String newFunc() {
BlackBox component = new BlackBox("something");
return component.get();
}
/**
* method with member method invoke
*/
public String outerFunc(String s) throws Exception {
return "{ \"res\": \"" + innerFunc(s) + staticFunc() + "\"}";
}
/**
* method with common method invoke
*/
public String commonFunc() {
return "anything".trim() + "__" + "anything".substring(1, 2) + "__" + "abc".startsWith("ab");
}
/**
* method with static method invoke
*/
public BlackBox getBox() {
return BlackBox.secretBox();
}
/**
* two methods invoke same private method
*/
public String callerOne() {
return callFromDifferentMethod();
}
public String callerTwo() {
return callFromDifferentMethod();
}
private static String staticFunc() {
return "_STATIC_TAIL";
}
private String innerFunc(String s) {
return "Nothing";
}
private String callFromDifferentMethod() {
return "realOne";
}
}

View File

@ -0,0 +1,32 @@
package com.alibaba.testable.demo;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
/**
* 演示与Robolectric配合使用
* Demonstrate using mock along with Robolectric
*/
public class DemoService extends Service {
static final String TAG = "DemoService";
SharedPreferences mPreference;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null && "start_foreground".equalsIgnoreCase(intent.getAction())) {
Log.d(TAG, "start service.");
} else if(intent != null && "stop_foreground".equalsIgnoreCase(intent.getAction())) {
Log.d(TAG, "stop service.");
}
return START_REDELIVER_INTENT;
}
}

View File

@ -1,4 +1,4 @@
package com.alibaba.demo.basic.model; package com.alibaba.testable.demo.model;
public class BlackBox extends Box implements Color { public class BlackBox extends Box implements Color {

View File

@ -1,4 +1,4 @@
package com.alibaba.demo.basic.model; package com.alibaba.testable.demo.model;
abstract public class Box { abstract public class Box {

View File

@ -1,4 +1,4 @@
package com.alibaba.demo.basic.model; package com.alibaba.testable.demo.model;
public interface Color { public interface Color {

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestableAndroidDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Testable Android Demo</string>
</resources>

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestableAndroidDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,122 @@
package com.alibaba.testable.demo;
import com.alibaba.testable.demo.model.BlackBox;
import com.alibaba.testable.core.annotation.MockNew;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.Test;
import java.util.concurrent.Executors;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static com.alibaba.testable.core.tool.TestableTool.MOCK_CONTEXT;
import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD;
import static org.junit.Assert.assertEquals;
/**
* 演示基本的Mock功能
* Demonstrate basic mock functionality
*/
public class DemoBasicTest {
private DemoBasic demoBasic = new DemoBasic();
public static class Mock {
@MockNew
private BlackBox createBlackBox(String text) {
return new BlackBox("mock_" + text);
}
@MockInvoke(targetClass = DemoBasic.class)
private String innerFunc(String text) {
return "mock_" + text;
}
@MockInvoke(targetClass = DemoBasic.class)
private String staticFunc() {
return "_MOCK_TAIL";
}
@MockInvoke(targetClass = String.class)
private String trim() {
return "trim_string";
}
@MockInvoke(targetClass = String.class, targetMethod = "substring")
private String sub(int i, int j) {
return "sub_string";
}
@MockInvoke(targetClass = String.class)
private boolean startsWith(String s) {
return false;
}
@MockInvoke(targetClass = BlackBox.class)
private BlackBox secretBox() {
return new BlackBox("not_secret_box");
}
@MockInvoke(targetClass = DemoBasic.class)
private String callFromDifferentMethod() {
if ("special_case".equals(MOCK_CONTEXT.get("case"))) {
return "mock_special";
}
switch (SOURCE_METHOD) {
case "callerOne":
return "mock_one";
default:
return "mock_others";
}
}
}
@Test
public void should_mock_new_object() {
assertEquals("mock_something", demoBasic.newFunc());
verifyInvoked("createBlackBox").with("something");
}
@Test
public void should_mock_member_method() throws Exception {
assertEquals("{ \"res\": \"mock_hello_MOCK_TAIL\"}", demoBasic.outerFunc("hello"));
verifyInvoked("innerFunc").with("hello");
verifyInvoked("staticFunc").with();
}
@Test
public void should_mock_common_method() {
assertEquals("trim_string__sub_string__false", demoBasic.commonFunc());
verifyInvoked("trim").withTimes(1);
verifyInvoked("sub").withTimes(1);
verifyInvoked("startsWith").withTimes(1);
}
@Test
public void should_mock_static_method() {
assertEquals("not_secret_box", demoBasic.getBox().get());
verifyInvoked("secretBox").withTimes(1);
}
@Test
public void should_get_source_method_name() throws Exception {
// synchronous
assertEquals("mock_one_mock_others", demoBasic.callerOne() + "_" + demoBasic.callerTwo());
// asynchronous
assertEquals("mock_one_mock_others",
Executors.newSingleThreadExecutor().submit(() -> demoBasic.callerOne() + "_" + demoBasic.callerTwo()).get());
verifyInvoked("callFromDifferentMethod").withTimes(4);
}
@Test
public void should_set_mock_context() throws Exception {
MOCK_CONTEXT.put("case", "special_case");
// synchronous
assertEquals("mock_special", demoBasic.callerOne());
// asynchronous
assertEquals("mock_special", Executors.newSingleThreadExecutor().submit(() -> demoBasic.callerOne()).get());
verifyInvoked("callFromDifferentMethod").withTimes(2);
}
}

View File

@ -0,0 +1,47 @@
package com.alibaba.testable.demo;
import android.content.Intent;
import android.util.Log;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 30)
public class DemoServiceTest {
private DemoService demoService;
public static class Mock {
@MockInvoke(targetClass = Log.class, targetMethod = "d")
public static int log(String tag, String msg) {
return 0;
}
}
@Before
public void setup() throws Exception {
demoService = Robolectric.setupService(DemoService.class);
}
@Test
public void testOnStartCommand() {
Intent intent = new Intent();
intent.setAction("start_foreground");
demoService.onStartCommand(intent, 0, 1);
verifyInvoked("log").with("DemoService", "start service.");
intent.setAction("stop_foreground");
demoService.onStartCommand(intent, 0, 1);
verifyInvoked("log").with("DemoService", "stop service.");
}
}

View File

@ -0,0 +1 @@
log.file = null

View File

@ -0,0 +1,28 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.32"
repositories {
mavenLocal()
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.0-alpha14"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official

View File

@ -0,0 +1,6 @@
#Fri Apr 30 14:35:40 CST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip

172
demo/android-demo/gradlew vendored Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
demo/android-demo/gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,2 @@
include ':app'
rootProject.name = "Testable Android Demo"

View File

@ -13,8 +13,8 @@ repositories {
dependencies { dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.6.2') testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
testImplementation('com.alibaba.testable:testable-all:0.5.2') testImplementation('com.alibaba.testable:testable-all:0.7.9')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.5.2') testAnnotationProcessor('com.alibaba.testable:testable-processor:0.7.9')
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {

View File

@ -11,8 +11,8 @@
<properties> <properties>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<junit.version>5.6.2</junit.version> <junit.version>5.9.1</junit.version>
<testable.version>0.5.2</testable.version> <testable.version>0.7.9</testable.version>
</properties> </properties>
<dependencies> <dependencies>
@ -35,7 +35,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.0.0-M7</version>
<configuration> <configuration>
<argLine>@{argLine} -javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine> <argLine>@{argLine} -javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine>
</configuration> </configuration>
@ -56,7 +56,7 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version> <version>0.8.8</version>
<executions> <executions>
<execution> <execution>
<id>prepare-agent</id> <id>prepare-agent</id>

View File

@ -0,0 +1,33 @@
package com.alibaba.demo.association;
/**
* 目标类此类中的一些调用将会被Mock掉
* Target class, some invocations inside this class will be mocked
*/
public class CookerService {
private static String hireSandwichCooker() {
return "Real-Sandwich-Cooker";
}
private static String hireHamburgerCooker() {
return "Real-Hamburger-Cooker";
}
private String cookSandwich() {
return "Real-Sandwich";
}
private String cookHamburger() {
return "Real-Hamburger";
}
public String prepareSandwich() {
return hireSandwichCooker() + " & " + cookSandwich();
}
public String prepareHamburger() {
return hireHamburgerCooker() + " & " + cookHamburger();
}
}

View File

@ -0,0 +1,18 @@
package com.alibaba.demo.association;
/**
* 被测类会访问`CookerService`里的方法
* Class to be tested, which will access methods in TargetService class
*/
public class SellerService {
private CookerService cookerService = new CookerService();
public String sellSandwich() {
return cookerService.prepareSandwich();
}
public String sellHamburger() {
return cookerService.prepareHamburger();
}
}

View File

@ -1,8 +1,7 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox; import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.demo.basic.model.BlackBox;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,7 +1,6 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox; import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.demo.basic.model.BlackBox;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;

View File

@ -46,7 +46,9 @@ public class DemoPrivateAccess {
* private member method with arguments * private member method with arguments
*/ */
private String privateFuncWithArgs(List<String> list, String str, int i) { private String privateFuncWithArgs(List<String> list, String str, int i) {
return list.stream().reduce((a, s) -> a + s).orElse("") + " + " + str + " + " + i; return list.stream().reduce((a, s) -> a + s).orElse("")
+ " + " + (str == null ? "null" : str)
+ " + " + i;
} }
} }

View File

@ -1,20 +1,17 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox; import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.demo.basic.model.Box; import com.alibaba.demo.basic.model.mock.Box;
import com.alibaba.demo.basic.model.Color; import com.alibaba.demo.basic.model.mock.Color;
import com.alibaba.demo.basic.model.BlackBox;
import com.alibaba.demo.basic.model.Box;
import com.alibaba.demo.basic.model.Color;
/** /**
* 演示父类变量引用子类对象时的Mock场景 * 演示父类变量引用子类对象时的Mock场景
* Demonstrate scenario of mocking method from sub-type object referred by parent-type variable * Demonstrate scenario of mocking method from sub-type object referred by parent-type variable
*/ */
public class DemoInherit { public class DemoReference {
/** /**
* call method overridden by sub class via parent class variable * call method overridden by subclass via parent class variable
*/ */
public Box putIntoBox() { public Box putIntoBox() {
Box box = new BlackBox(""); Box box = new BlackBox("");
@ -23,7 +20,7 @@ public class DemoInherit {
} }
/** /**
* call method overridden by sub class via sub class variable * call method overridden by subclass via subclass variable
*/ */
public BlackBox putIntoBlackBox() { public BlackBox putIntoBlackBox() {
BlackBox box = new BlackBox(""); BlackBox box = new BlackBox("");
@ -40,7 +37,7 @@ public class DemoInherit {
} }
/** /**
* call method defined in parent class via sub class variable * call method defined in parent class via subclass variable
*/ */
public String getFromBlackBox() { public String getFromBlackBox() {
BlackBox box = new BlackBox("data"); BlackBox box = new BlackBox("data");
@ -56,10 +53,18 @@ public class DemoInherit {
} }
/** /**
* call method defined in interface via sub class variable * call method defined in interface via subclass variable
*/ */
public String getColorViaBox() { public String getColorViaBox() {
BlackBox box = new BlackBox(""); BlackBox box = new BlackBox("");
return box.getColor(); return box.getColor();
} }
/**
* call method defined in interface via subclass variable
*/
public String getColorIdxViaColor() {
Color color = new BlackBox("");
return color.getColorIndex();
}
} }

View File

@ -0,0 +1,7 @@
package com.alibaba.demo.basic.model.mock;
public interface BasicColor {
String getColorIndex();
}

View File

@ -0,0 +1,27 @@
package com.alibaba.demo.basic.model.mock;
public class BlackBox extends Box implements Color {
public BlackBox(String data) {
this.data = data;
}
public static BlackBox secretBox() {
return new BlackBox("secret");
}
@Override
public void put(String something) {
data = something;
}
@Override
public String getColor() {
return "black";
}
@Override
public String getColorIndex() {
return "idx";
}
}

View File

@ -0,0 +1,13 @@
package com.alibaba.demo.basic.model.mock;
abstract public class Box {
protected String data;
abstract public void put(String something);
public String get() {
return data;
}
}

View File

@ -0,0 +1,7 @@
package com.alibaba.demo.basic.model.mock;
public interface Color extends BasicColor {
String getColor();
}

View File

@ -0,0 +1,47 @@
package com.alibaba.demo.basic.model.omni;
public class Child {
/**
* 我是一个私有的构造方法
* This class have only private constructor
*/
private Child() {
}
// ---------- 内部成员字段 ----------
private GrandChild grandChild;
private InnerChild subChild;
/**
* 这是一个私有内部类
* An private inner class
*/
private class InnerChild {
private String secret;
}
/* ---------------------------------------
以下Getters/Setters方法仅为便于功能演示而添加
并非OmniConstructor或OmniAccessor功能所需
--------------------------------------- */
public GrandChild getGrandChild() {
return grandChild;
}
public void setGrandChild(GrandChild grandChild) {
this.grandChild = grandChild;
}
public InnerChild getSubChild() {
return subChild;
}
public void setSubChild(InnerChild subChild) {
this.subChild = subChild;
}
}

View File

@ -0,0 +1,31 @@
package com.alibaba.demo.basic.model.omni;
public class GrandChild {
// ---------- 内部成员字段 ----------
private int value;
private String content;
/* ---------------------------------------
以下Getters/Setters方法仅为便于功能演示而添加
并非OmniConstructor或OmniAccessor功能所需
--------------------------------------- */
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,40 @@
package com.alibaba.demo.basic.model.omni;
public class Parent {
/**
* 我是一个虽然存在但无法正常使用的构造方法
* This class have constructor with exception throw
*/
public Parent() {
throw new IllegalArgumentException();
}
// ---------- 内部成员字段 ----------
private Child child;
private Child[] children;
/* ---------------------------------------
以下Getters/Setters方法仅为便于功能演示而添加
并非OmniConstructor或OmniAccessor功能所需
--------------------------------------- */
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
public Child[] getChildren() {
return children;
}
public void setChildren(Child[] children) {
this.children = children;
}
}

View File

@ -0,0 +1,25 @@
package com.alibaba.demo.inherit;
/**
* 演示使用@MockContainer注解实现Mock容器类的多重继承
* Demonstrate multiple inherit of mock container class with @MockContainer annotation
*/
public class DemoMultipleInherit {
private String prefix() {
return "ori_";
}
private String middle() {
return "gin";
}
private String suffix(int some, String more, Object[] parameters) {
return "_al";
}
public String entry() {
return prefix() + middle() + suffix(0, null, null);
}
}

View File

@ -0,0 +1,21 @@
package com.alibaba.demo.inherit;
/**
* 演示使用extends关键字实现Mock容器类的继承
* Demonstrate inherit of mock container class
*/
public class DemoSingleInherit {
private String prefix() {
return "re_";
}
private String suffix() {
return "_al";
}
public String entry(String word) {
return prefix() + word + suffix();
}
}

View File

@ -0,0 +1,42 @@
package com.alibaba.demo.lambda;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author jim
*/
public interface BaseDemo {
default void blackHole(Object... ignore) {}
default void consumesRun(Runnable r) {
r.run();
}
default void consumesFunction0(Runnable f) {
f.run();
}
default <T> void consumesFunction1(Consumer<T> f) {
f.accept(null);
}
default <T, R> void consumesFunction2(Function<T, R> f) {
f.apply(null);
}
default <T1, T2, R> void consumesFunction3(BiFunction<T1, T2, R> f) {
f.apply(null, null);
}
default <T> void consumesSupplier(Supplier<T> supplier) {
supplier.get();
}
default <T, R> void consumesTwoFunction2(Function<T, R> f1, Function<T, R> f2) {
f1.apply(null);
f2.apply(null);
}
}

View File

@ -0,0 +1,121 @@
package com.alibaba.demo.lambda;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author jim
*/
@SuppressWarnings("SimplifyStreamApiCallChains")
public class CollectionListCodeDemo implements BaseDemo {
public void list() {
List<User> userList = getUsers();
double d = userList.stream()
.map(v -> v)
.map(v -> Function.<User>identity().apply(v))
.map(User::getId)
.mapToDouble(Double::valueOf)
.reduce(0, Double::sum);
//.reduce(0, (v1, v2) -> v1 + v2);
blackHole(d);
blackHole(userList.stream()
.map(User::getId)
.mapToLong(Long::valueOf)
.reduce(0, Long::sum));
blackHole(userList.stream()
.map(User::getId)
.mapToInt(Long::intValue)
.reduce(0, Integer::sum));
Map<Long, User> map = userList.stream()
.filter(User::isActive)
.collect(Collectors.toMap(User::getId, Function.identity(), (v1, v2) -> v1));
blackHole(map);
List<User> l1 = userList.stream()
.collect(Collectors.toList())
.stream()
.collect(Collectors.toSet())
.stream()
.collect(Collectors.groupingBy(User::getName))
.entrySet()
.stream()
.filter(v -> v.getValue().stream().anyMatch(User::isActive))
.map(Map.Entry::getValue)
.flatMap(Collection::parallelStream)
.collect(Collectors.groupingBy(User::getId))
.values()
.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
blackHole(l1);
userList.stream()
.map(User::isActive)
.reduce(Boolean::logicalAnd)
.ifPresent(this::blackHole);
}
private List<User> getUsers() {
List<User> userList = new ArrayList<>();
for (int i=0; i<10; i++) {
userList.add(getUser(i));
}
return userList;
}
private User getUser(int index) {
User u1 = new User();
u1.id = (long)index;
u1.name = "u" + index;
u1.age = index;
u1.active = true;
return u1;
}
private static class User {
private Long id;
private String name;
private int age;
private boolean active;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
}

View File

@ -0,0 +1,9 @@
package com.alibaba.demo.lambda;
/**
* @author jim
*/
@FunctionalInterface
public interface Function1Throwable<T, R> {
R apply(T t) throws Throwable;
}

View File

@ -0,0 +1,86 @@
package com.alibaba.demo.lambda;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* @author jim
*/
public class InvokeInterfaceDemo implements BaseDemo {
public void collectionInterfaceDefaultOrStatic() {
blackHole(collectionStreamTest());
blackHole(arraysStreamTest());
}
public void interfaceDefault() {
ILambda l = new LambdaFoo();
consumesRun(l::run);
consumesFunction1(l::function1);
}
public void interfaceStatic() {
consumesRun(ILambda::staticRun);
consumesFunction1(ILambda::staticFunction1);
}
public Object collectionStreamTest() {
List<List<String>> testList = new ArrayList<>();
List<String> fooList = new ArrayList<>();
fooList.add("123");
fooList.add("456");
testList.add(fooList);
return testList.stream()
//.flatMap(v -> v.stream())
.flatMap(Collection::stream)
.map(Double::valueOf)
.map(BigDecimal::new)
.reduce(BigDecimal::add);
}
public Object arraysStreamTest() {
List<String[]> zz = new ArrayList<>();
zz.add(new String[]{"1", "2", "3"});
return zz.stream()
.flatMap(Arrays::stream)
.map(Double::valueOf)
.map(BigDecimal::new)
.reduce(BigDecimal::add);
}
public void objectStaticMethodReference() {
List<Boolean> f = new ArrayList<>();
f.add(false);
f.add(false);
f.add(false);
blackHole(f.stream()
.reduce(Boolean::logicalAnd)
.get()
);
}
public interface ILambda {
default void run() {
}
default void function1(String s) {
}
static void staticRun() {
}
static void staticFunction1(String s) {
}
}
public static class LambdaFoo implements ILambda {
}
}

View File

@ -0,0 +1,243 @@
package com.alibaba.demo.lambda;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author jimca
*/
@SuppressWarnings({"WrapperTypeMayBePrimitive", "ResultOfMethodCallIgnored", "MismatchedReadAndWriteOfArray", "unused"})
public class InvokeVirtualDemo {
public void string1() {
String s = "";
consumesFunction2(s::contains);
}
public void string2() {
String s = "";
consumesFunction2(s::charAt);
}
public void string3() {
String s = "";
consumesFunction0(s::notify);
}
public void byte1() {
Byte s = 1;
consumesSupplier(s::floatValue);
}
public void byte2() {
Byte s = 1;
consumesFunction2(s::compareTo);
}
public void byte3() {
Byte s = 1;
consumesFunction0(s::notify);
}
public void char1() {
Character s = 1;
consumesFunction0(s::toString);
}
public void char2() {
Character s = 1;
consumesFunction2(s::compareTo);
}
public void char3() {
Character s = 1;
consumesFunction0(s::notify);
}
public void short1() {
Short s = 1;
consumesFunction0(s::toString);
}
public void short2() {
Short s = 1;
consumesFunction2(s::compareTo);
}
public void short3() {
Short s = 1;
consumesFunction0(s::notify);
}
public void int1() {
Integer s = 1;
consumesFunction0(s::toString);
}
public void int2() {
Integer s = 1;
consumesFunction2(s::compareTo);
}
public void int3() {
Integer s = 1;
consumesFunction0(s::notify);
}
public void long1() {
Long s = 1L;
consumesFunction0(s::toString);
}
public void long2() {
Long s = 1L;
consumesFunction2(s::compareTo);
}
public void long3() {
Long s = 1L;
consumesFunction0(s::notify);
}
public void float1() {
Float s = 1f;
consumesFunction0(s::toString);
}
public void float2() {
Float s = 1f;
consumesFunction2(s::compareTo);
}
public void float3() {
Float s = 1f;
consumesFunction0(s::notify);
}
public void double1() {
Double s = 1d;
consumesFunction0(s::toString);
}
public void double2() {
Double s = 1d;
consumesFunction2(s::compareTo);
}
public void double3() {
Double s = 1d;
consumesFunction0(s::notify);
}
public void bool1() {
Boolean s = true;
consumesFunction0(s::toString);
}
public void bool2() {
Boolean s = true;
consumesFunction2(s::compareTo);
}
public void bool3() {
Boolean s = true;
consumesFunction0(s::notify);
}
public void stringArray1() {
String[] array = new String[]{""};
consumesFunction0(array::toString);
}
public void stringArray2() {
String[] array = new String[]{""};
consumesFunction2(array::equals);
}
public void stringArray3() {
String[] array = new String[]{""};
consumesFunction0(array::notify);
}
public void intArray1() {
int[] array = new int[]{1};
consumesFunction0(array::toString);
}
public void intArray2() {
int[] array = new int[]{1};
consumesFunction2(array::equals);
}
public void intArray3() {
int[] array = new int[]{1};
consumesFunction0(array::notify);
}
public void mul() {
String s = "";
consumesTwoFunction2(s::contains, s::contains);
}
public void externalClass() {
LambdaDemo lambdaDemo = new LambdaDemo();
consumesFunction0(lambdaDemo::methodReference0);
}
public void interClass() {
A a = new A();
consumesFunction2(a::m1);
consumesFunction2(a::m2);
}
public void function3() {
InvokeVirtualDemo invokeVirtualDemo = new InvokeVirtualDemo();
consumesFunction3(invokeVirtualDemo::f3);
}
public Boolean f3(String s1, Long l) {
return false;
}
private void consumesFunction0(Runnable f) {
f.run();
}
private <T> void consumesFunction1(Consumer<T> f) {
f.accept(null);
}
private <T, R> void consumesFunction2(Function<T, R> f) {
f.apply(null);
}
private <T1, T2, R> void consumesFunction3(BiFunction<T1, T2, R> f) {
f.apply(null, null);
}
private <T> void consumesSupplier(Supplier<T> supplier) {
supplier.get();
}
private <T, R> void consumesTwoFunction2(Function<T, R> f1, Function<T, R> f2) {
f1.apply(null);
f2.apply(null);
}
public static class A {
public String m1(int i) {
return "";
}
public String m2(Integer i) {
return "";
}
}
}

View File

@ -0,0 +1,218 @@
package com.alibaba.demo.lambda;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* @author jim
*/
@SuppressWarnings("unused")
public class LambdaDemo {
public void methodReference() {
consumesRun(this::run);
}
private void consumesRun(Runnable r) {
r.run();
}
private void run() {
blackHole();
}
public String methodReference0() {
return consumes0(this::function0);
}
private String consumes0(Supplier<String> function0) {
return function0.get();
}
private String function0() {
return "Hello";
}
public String methodReference1() {
return consumes1(this::function1);
}
private String consumes1(Function<Integer, String> function) {
return function.apply(1);
}
private String function1(Integer i) {
return String.valueOf(i);
}
public String methodReferenceThrows() {
return consumesThrows(this::function1Throwable);
}
private String consumesThrows(Function1Throwable<Integer, String> function) {
try {
return function.apply(1);
}catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("RedundantThrows")
private String function1Throwable(Integer i) throws Throwable{
return String.valueOf(i);
}
public String methodReference2() {
return consumes2(this::function2);
}
private String consumes2(BiFunction<Integer, Double, String> function) {
return function.apply(1, .2);
}
private String function2(Integer i, Double d) {
return i + String.valueOf(d);
}
public String staticMethodReference1() {
return consumes1(StaticMethod::function1);
}
public String staticMethodReference2() {
return consumes2(StaticMethod::function2);
}
public void lambdaRun() {
consumes(() -> System.out.println("lambdaRun"));
}
private void consumes(Runnable o) {
o.run();
}
public void methodReferenceNew() {
Object o = consumes(Object::new);
blackHole(o);
}
private <T> T consumes(Supplier<T> s) {
return s.get();
}
private void blackHole(Object... ignore) {}
public void array() {
Function<Boolean[], Boolean[]> arrayBooleanFunction = this::arrayBooleanFunction;
Function<boolean[], boolean[]> arrayBooleanFunction1 = this::arrayBoolFunction;
Function<Byte[], Byte[]> byteFunction = this::arrayByteFunction;
Function<byte[], byte[]> byteFunction1 = this::arrayByteFunction;
Function<Character[], Character[]> charFunction = this::arrayCharFunction;
Function<char[], char[]> charFunction1 = this::arrayCharFunction;
Function<Short[], Short[]> shortFunction = this::arrayShortFunction;
Function<short[], short[]> shortFunction1 = this::arrayShortFunction;
Function<int[], int[]> intFunction = this::arrayIntFunction;
Function<Integer[], Integer[]> intFunction1 = this::arrayIntegerFunction;
Function<long[], long[]> longFunction = this::arrayLongFunction;
Function<Long[], Long[]> longFunction1 = this::arrayLongFunction;
Function<Float[], Float[]> floatFunction = this::arrayFloatFunction;
Function<float[], float[]> floatFunction1 = this::arrayFloatFunction;
Function<Double[], Double[]> doubleFunction = this::arrayDoubleFunction;
Function<double[], double[]> doubleFunction1 = this::arrayDoubleFunction;
blackHole(arrayBooleanFunction, arrayBooleanFunction1,
byteFunction, byteFunction1, charFunction, charFunction1, shortFunction, shortFunction1,
intFunction, intFunction1, longFunction, longFunction1, floatFunction, floatFunction1, doubleFunction,
doubleFunction1
);
}
private int[] arrayIntFunction(int[] arg) {
return arg;
}
private Integer[] arrayIntegerFunction(Integer[] arg) {
return arg;
}
private boolean[] arrayBoolFunction(boolean[] arg) {
return arg;
}
private Boolean[] arrayBooleanFunction(Boolean[] arg) {
return arg;
}
private byte[] arrayByteFunction(byte[] arg) {
return arg;
}
private Byte[] arrayByteFunction(Byte[] arg) {
return arg;
}
private char[] arrayCharFunction(char[] arg) {
return arg;
}
private Character[] arrayCharFunction(Character[] arg) {
return arg;
}
private short[] arrayShortFunction(short[] arg) {
return arg;
}
private Short[] arrayShortFunction(Short[] arg) {
return arg;
}
private long[] arrayLongFunction(long[] arg) {
return arg;
}
private Long[] arrayLongFunction(Long[] arg) {
return arg;
}
private float[] arrayFloatFunction(float[] arg) {
return arg;
}
private Float[] arrayFloatFunction(Float[] arg) {
return arg;
}
private double[] arrayDoubleFunction(double[] arg) {
return arg;
}
private Double[] arrayDoubleFunction(Double[] arg) {
return arg;
}
public void generic() {
Function<?, ?> genericFunction = this::genericFunction;
blackHole(genericFunction);
}
public <T, R> R genericFunction(T arg) {
//noinspection unchecked
return (R)arg;
}
private void collects() {
long l = Stream.of("1", "2", "3")
.filter(v -> !"2".equals(v))
.map(Long::parseLong)
.peek(this::blackHole)
.map(v -> new ArrayList<Long>(){{add(v);}})
.flatMap(Collection::stream)
.mapToLong(Long::valueOf)
.sum();
blackHole(l);
}
}

View File

@ -0,0 +1,33 @@
package com.alibaba.demo.lambda;
/**
* @author jim
*/
public class StaticInstanceReference implements BaseDemo {
private static final StaticClassA STATIC_CLASS_A = new StaticClassA();
public void staticMethodReference() {
consumesRun(STATIC_CLASS_A::doIt);
consumesFunction1(STATIC_CLASS_A::function1);
consumesFunction2(STATIC_CLASS_A::function2);
consumesFunction3(STATIC_CLASS_A::function3);
}
public static class StaticClassA {
public void doIt() {
}
public void function1(String s) {
}
public Integer function2(String s) {
return 1;
}
public Integer function3(String s, Double d) {
return 1;
}
}
}

View File

@ -0,0 +1,15 @@
package com.alibaba.demo.lambda;
/**
* @author jim
*/
public class StaticMethod {
public static String function1(Integer i) {
return "static" + i;
}
public static String function2(Integer i, Double d) {
return "static" + i + d;
}
}

View File

@ -0,0 +1,27 @@
package com.alibaba.demo.association;
import com.alibaba.testable.core.annotation.MockInvoke;
import com.alibaba.testable.core.model.MockScope;
class CookerServiceMock {
@MockInvoke(targetClass = CookerService.class)
public static String hireSandwichCooker() {
return "Fake-Sandwich-Cooker";
}
@MockInvoke(targetClass = CookerService.class, scope = MockScope.ASSOCIATED)
public static String hireHamburgerCooker() {
return "Fake-Hamburger-Cooker";
}
@MockInvoke(targetClass = CookerService.class)
private String cookSandwich() {
return "Faked-Sandwich";
}
@MockInvoke(targetClass = CookerService.class, scope = MockScope.ASSOCIATED)
private String cookHamburger() {
return "Faked-Hamburger";
}
}

View File

@ -0,0 +1,21 @@
package com.alibaba.demo.association;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class SellerServiceTest {
private SellerService sellerService = new SellerService();
@Test
void should_sell_sandwich() {
assertEquals("Fake-Sandwich-Cooker & Faked-Sandwich", sellerService.sellSandwich());
}
@Test
void should_sell_hamburger() {
assertEquals("Real-Hamburger-Cooker & Real-Hamburger", sellerService.sellHamburger());
}
}

View File

@ -1,98 +0,0 @@
package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox;
import com.alibaba.demo.basic.model.Box;
import com.alibaba.demo.basic.model.Color;
import com.alibaba.testable.core.annotation.MockMethod;
import com.alibaba.demo.basic.DemoInherit;
import com.alibaba.demo.basic.model.BlackBox;
import com.alibaba.demo.basic.model.Box;
import com.alibaba.demo.basic.model.Color;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvokeVerifier.verify;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* 演示父类变量引用子类对象时的Mock场景
* Demonstrate scenario of mocking method from sub-type object referred by parent-type variable
*/
class DemoInheritTest {
private DemoInherit demoInherit = new DemoInherit();
public static class Mock {
@MockMethod(targetMethod = "put")
private void put_into_box(Box self, String something) {
self.put("put_" + something + "_into_box");
}
@MockMethod(targetMethod = "put")
private void put_into_blackbox(BlackBox self, String something) {
self.put("put_" + something + "_into_blackbox");
}
@MockMethod(targetMethod = "get")
private String get_from_box(Box self) {
return "get_from_box";
}
@MockMethod(targetMethod = "get")
private String get_from_blackbox(BlackBox self) {
return "get_from_blackbox";
}
@MockMethod(targetMethod = "getColor")
private String get_color_from_color(Color self) {
return "color_from_color";
}
@MockMethod(targetMethod = "getColor")
private String get_color_from_blackbox(BlackBox self) {
return "color_from_blackbox";
}
}
@Test
void should_able_to_mock_call_sub_object_method_by_parent_object() {
BlackBox box = (BlackBox)demoInherit.putIntoBox();
verify("put_into_box").withTimes(1);
assertEquals("put_data_into_box", box.get());
}
@Test
void should_able_to_mock_call_sub_object_method_by_sub_object() {
BlackBox box = demoInherit.putIntoBlackBox();
verify("put_into_blackbox").withTimes(1);
assertEquals("put_data_into_blackbox", box.get());
}
@Test
void should_able_to_mock_call_parent_object_method_by_parent_object() {
String content = demoInherit.getFromBox();
verify("get_from_box").withTimes(1);
assertEquals("get_from_box", content);
}
@Test
void should_able_to_mock_call_parent_object_method_by_sub_object() {
String content = demoInherit.getFromBlackBox();
verify("get_from_blackbox").withTimes(1);
assertEquals("get_from_blackbox", content);
}
@Test
void should_able_to_mock_call_interface_method_by_interface_object() {
String color = demoInherit.getColorViaColor();
verify("get_color_from_color").withTimes(1);
assertEquals("color_from_color", color);
}
@Test
void should_able_to_mock_call_interface_method_by_sub_class_object() {
String color = demoInherit.getColorViaBox();
verify("get_color_from_blackbox").withTimes(1);
assertEquals("color_from_blackbox", color);
}
}

View File

@ -1,6 +1,6 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -12,14 +12,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
class DemoInnerClassTest { class DemoInnerClassTest {
public static class Mock { public static class Mock {
@MockMethod(targetClass = DemoInnerClass.class) @MockInvoke(targetClass = DemoInnerClass.class)
String methodToBeMock() { String methodToBeMock() {
return "MockedCall"; return "MockedCall";
} }
} }
@Test @Test
void should_able_to_mock_invoke_inside_inner_class() throws Exception { void should_mock_invoke_inside_inner_class() throws Exception {
DemoInnerClass demo = new DemoInnerClass(); DemoInnerClass demo = new DemoInnerClass();
assertEquals("MockedCall", demo.callInnerDemo()); assertEquals("MockedCall", demo.callInnerDemo());
assertEquals("MockedCall", demo.callAnonymousInner()); assertEquals("MockedCall", demo.callAnonymousInner());

View File

@ -1,14 +1,12 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox; import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
import com.alibaba.testable.core.error.VerifyFailedError; import com.alibaba.testable.core.error.VerifyFailedError;
import com.alibaba.demo.basic.DemoMatcher;
import com.alibaba.demo.basic.model.BlackBox;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvokeMatcher.*; import static com.alibaba.testable.core.matcher.InvocationMatcher.*;
import static com.alibaba.testable.core.matcher.InvokeVerifier.verify; import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
/** /**
@ -20,62 +18,62 @@ class DemoMatcherTest {
private DemoMatcher demoMatcher = new DemoMatcher(); private DemoMatcher demoMatcher = new DemoMatcher();
public static class Mock { public static class Mock {
@MockMethod(targetMethod = "methodToBeMocked") @MockInvoke(targetMethod = "methodToBeMocked")
private void methodWithoutArgument(DemoMatcher self) {} private void methodWithoutArgument(DemoMatcher self) {}
@MockMethod(targetMethod = "methodToBeMocked") @MockInvoke(targetMethod = "methodToBeMocked")
private void methodWithArguments(DemoMatcher self, Object a1, Object a2) {} private void methodWithArguments(DemoMatcher self, Object a1, Object a2) {}
@MockMethod(targetMethod = "methodToBeMocked") @MockInvoke(targetMethod = "methodToBeMocked")
private void methodWithArrayArgument(DemoMatcher self, Object[] a) {} private void methodWithArrayArgument(DemoMatcher self, Object[] a) {}
} }
@Test @Test
void should_match_no_argument() { void should_match_no_argument() {
demoMatcher.callMethodWithoutArgument(); demoMatcher.callMethodWithoutArgument();
verify("methodWithoutArgument").withTimes(1); verifyInvoked("methodWithoutArgument").withTimes(1);
demoMatcher.callMethodWithoutArgument(); demoMatcher.callMethodWithoutArgument();
verify("methodWithoutArgument").withTimes(2); verifyInvoked("methodWithoutArgument").withTimes(2);
} }
@Test @Test
void should_match_number_arguments() { void should_match_number_arguments() {
demoMatcher.callMethodWithNumberArguments(); demoMatcher.callMethodWithNumberArguments();
verify("methodWithArguments").without(anyString(), 2); verifyInvoked("methodWithArguments").without(anyString(), 2);
verify("methodWithArguments").withInOrder(anyInt(), 2); verifyInvoked("methodWithArguments").withInOrder(anyInt(), 2);
verify("methodWithArguments").withInOrder(anyLong(), anyNumber()); verifyInvoked("methodWithArguments").withInOrder(anyLong(), anyNumber());
verify("methodWithArguments").with(1.0, anyMapOf(Integer.class, Float.class)); verifyInvoked("methodWithArguments").with(1.0, anyMapOf(Integer.class, Float.class));
verify("methodWithArguments").with(anyList(), anySetOf(Float.class)); verifyInvoked("methodWithArguments").with(anyList(), anySetOf(Float.class));
verify("methodWithArguments").with(anyList(), anyListOf(Float.class)); verifyInvoked("methodWithArguments").with(anyList(), anyListOf(Float.class));
verify("methodWithArrayArgument").with(anyArrayOf(Long.class)); verifyInvoked("methodWithArrayArgument").with(anyArrayOf(Long.class));
verify("methodWithArrayArgument").with(anyArray()); verifyInvoked("methodWithArrayArgument").with(anyArray());
} }
@Test @Test
void should_match_string_arguments() { void should_match_string_arguments() {
demoMatcher.callMethodWithStringArgument(); demoMatcher.callMethodWithStringArgument();
verify("methodWithArguments").with(startsWith("he"), endsWith("ld")); verifyInvoked("methodWithArguments").with(startsWith("he"), endsWith("ld"));
verify("methodWithArguments").with(contains("stab"), matches("m.[cd]k")); verifyInvoked("methodWithArguments").with(contains("stab"), matches("m.[cd]k"));
verify("methodWithArrayArgument").with(anyArrayOf(String.class)); verifyInvoked("methodWithArrayArgument").with(anyArrayOf(String.class));
} }
@Test @Test
void should_match_object_arguments() { void should_match_object_arguments() {
demoMatcher.callMethodWithObjectArgument(); demoMatcher.callMethodWithObjectArgument();
verify("methodWithArguments").withInOrder(any(BlackBox.class), any(BlackBox.class)); verifyInvoked("methodWithArguments").withInOrder(any(BlackBox.class), any(BlackBox.class));
verify("methodWithArguments").withInOrder(nullable(BlackBox.class), nullable(BlackBox.class)); verifyInvoked("methodWithArguments").withInOrder(nullable(BlackBox.class), nullable(BlackBox.class));
verify("methodWithArguments").withInOrder(isNull(), notNull()); verifyInvoked("methodWithArguments").withInOrder(isNull(), notNull());
} }
@Test @Test
void should_match_with_times() { void should_match_with_times() {
demoMatcher.callMethodWithNumberArguments(); demoMatcher.callMethodWithNumberArguments();
verify("methodWithArguments").with(anyNumber(), any()).times(3); verifyInvoked("methodWithArguments").with(anyNumber(), any()).times(3);
demoMatcher.callMethodWithNumberArguments(); demoMatcher.callMethodWithNumberArguments();
boolean gotError = false; boolean gotError = false;
try { try {
verify("methodWithArguments").with(anyNumber(), any()).times(4); verifyInvoked("methodWithArguments").with(anyNumber(), any()).times(4);
} catch (VerifyFailedError e) { } catch (VerifyFailedError e) {
gotError = true; gotError = true;
} }

View File

@ -1,15 +1,13 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.BlackBox; import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.testable.core.annotation.MockConstructor; import com.alibaba.testable.core.annotation.MockNew;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
import com.alibaba.demo.basic.model.BlackBox;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import static com.alibaba.testable.core.matcher.InvokeVerifier.verify; import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static com.alibaba.testable.core.tool.TestableTool.MOCK_CONTEXT; import static com.alibaba.testable.core.tool.TestableTool.MOCK_CONTEXT;
import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD; import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -23,42 +21,42 @@ class DemoMockTest {
private DemoMock demoMock = new DemoMock(); private DemoMock demoMock = new DemoMock();
public static class Mock { public static class Mock {
@MockConstructor @MockNew
private BlackBox createBlackBox(String text) { private BlackBox createBlackBox(String text) {
return new BlackBox("mock_" + text); return new BlackBox("mock_" + text);
} }
@MockMethod(targetClass = DemoMock.class) @MockInvoke(targetClass = DemoMock.class)
private String innerFunc(String text) { private String innerFunc(String text) {
return "mock_" + text; return "mock_" + text;
} }
@MockMethod(targetClass = DemoMock.class) @MockInvoke(targetClass = DemoMock.class)
private String staticFunc() { private String staticFunc() {
return "_MOCK_TAIL"; return "_MOCK_TAIL";
} }
@MockMethod(targetClass = String.class) @MockInvoke(targetClass = String.class)
private String trim() { private String trim() {
return "trim_string"; return "trim_string";
} }
@MockMethod(targetClass = String.class, targetMethod = "substring") @MockInvoke(targetClass = String.class, targetMethod = "substring")
private String sub(int i, int j) { private String sub(int i, int j) {
return "sub_string"; return "sub_string";
} }
@MockMethod(targetClass = String.class) @MockInvoke(targetClass = String.class)
private boolean startsWith(String s) { private boolean startsWith(String s) {
return false; return false;
} }
@MockMethod(targetClass = BlackBox.class) @MockInvoke(targetClass = BlackBox.class)
private BlackBox secretBox() { private BlackBox secretBox() {
return new BlackBox("not_secret_box"); return new BlackBox("not_secret_box");
} }
@MockMethod(targetClass = DemoMock.class) @MockInvoke(targetClass = DemoMock.class)
private String callFromDifferentMethod() { private String callFromDifferentMethod() {
if ("special_case".equals(MOCK_CONTEXT.get("case"))) { if ("special_case".equals(MOCK_CONTEXT.get("case"))) {
return "mock_special"; return "mock_special";
@ -73,50 +71,50 @@ class DemoMockTest {
} }
@Test @Test
void should_able_to_mock_new_object() { void should_mock_new_object() {
assertEquals("mock_something", demoMock.newFunc()); assertEquals("mock_something", demoMock.newFunc());
verify("createBlackBox").with("something"); verifyInvoked("createBlackBox").with("something");
} }
@Test @Test
void should_able_to_mock_member_method() throws Exception { void should_mock_member_method() throws Exception {
assertEquals("{ \"res\": \"mock_hello_MOCK_TAIL\"}", demoMock.outerFunc("hello")); assertEquals("{ \"res\": \"mock_hello_MOCK_TAIL\"}", demoMock.outerFunc("hello"));
verify("innerFunc").with("hello"); verifyInvoked("innerFunc").with("hello");
verify("staticFunc").with(); verifyInvoked("staticFunc").with();
} }
@Test @Test
void should_able_to_mock_common_method() { void should_mock_common_method() {
assertEquals("trim_string__sub_string__false", demoMock.commonFunc()); assertEquals("trim_string__sub_string__false", demoMock.commonFunc());
verify("trim").withTimes(1); verifyInvoked("trim").withTimes(1);
verify("sub").withTimes(1); verifyInvoked("sub").withTimes(1);
verify("startsWith").withTimes(1); verifyInvoked("startsWith").withTimes(1);
} }
@Test @Test
void should_able_to_mock_static_method() { void should_mock_static_method() {
Assertions.assertEquals("not_secret_box", demoMock.getBox().get()); assertEquals("not_secret_box", demoMock.getBox().get());
verify("secretBox").withTimes(1); verifyInvoked("secretBox").withTimes(1);
} }
@Test @Test
void should_able_to_get_source_method_name() throws Exception { void should_get_source_method_name() throws Exception {
// synchronous // synchronous
assertEquals("mock_one_mock_others", demoMock.callerOne() + "_" + demoMock.callerTwo()); assertEquals("mock_one_mock_others", demoMock.callerOne() + "_" + demoMock.callerTwo());
// asynchronous // asynchronous
assertEquals("mock_one_mock_others", assertEquals("mock_one_mock_others",
Executors.newSingleThreadExecutor().submit(() -> demoMock.callerOne() + "_" + demoMock.callerTwo()).get()); Executors.newSingleThreadExecutor().submit(() -> demoMock.callerOne() + "_" + demoMock.callerTwo()).get());
verify("callFromDifferentMethod").withTimes(4); verifyInvoked("callFromDifferentMethod").withTimes(4);
} }
@Test @Test
void should_able_to_set_mock_context() throws Exception { void should_set_mock_context() throws Exception {
MOCK_CONTEXT.put("case", "special_case"); MOCK_CONTEXT.put("case", "special_case");
// synchronous // synchronous
assertEquals("mock_special", demoMock.callerOne()); assertEquals("mock_special", demoMock.callerOne());
// asynchronous // asynchronous
assertEquals("mock_special", Executors.newSingleThreadExecutor().submit(() -> demoMock.callerOne()).get()); assertEquals("mock_special", Executors.newSingleThreadExecutor().submit(() -> demoMock.callerOne()).get());
verify("callFromDifferentMethod").withTimes(2); verifyInvoked("callFromDifferentMethod").withTimes(2);
} }
} }

View File

@ -0,0 +1,91 @@
package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.omni.Child;
import com.alibaba.demo.basic.model.omni.Parent;
import com.alibaba.testable.core.tool.OmniAccessor;
import com.alibaba.testable.core.tool.OmniConstructor;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* 演示快速创建任意对象和使用路径访问成员
* Demonstrate quick object construction and access members by path
*/
class DemoOmniMethodsTest {
@Test
void should_construct_any_class() {
Parent parent = OmniConstructor.newInstance(Parent.class);
// 任意深度的子孙成员对象都不为空
assertNotNull(parent.getChild().getGrandChild().getContent());
// 所有基础类型初始化为默认数值
assertEquals(0, parent.getChild().getGrandChild().getValue());
assertEquals("", parent.getChild().getGrandChild().getContent());
// 所有数组类型初始化为空数组
assertEquals(0, parent.getChildren().length);
}
@Test
void should_get_any_member() {
Parent parent = OmniConstructor.newInstance(Parent.class);
parent.setChildren(OmniConstructor.newArray(Child.class, 3));
parent.getChild().getGrandChild().setContent("from child");
parent.getChildren()[0].getGrandChild().setContent("from 1st children");
parent.getChildren()[1].getGrandChild().setContent("from 2nd children");
parent.getChildren()[2].getGrandChild().setContent("from 3rd children");
// 使用成员名称快速读取成员对象
List<String> contents = OmniAccessor.get(parent, "content");
assertEquals(4, contents.size());
assertEquals("from child", contents.get(0));
assertEquals("from 1st children", contents.get(1));
assertEquals("from 2nd children", contents.get(2));
assertEquals("from 3rd children", contents.get(3));
// 使用成员类型快速读取成员对象
contents = OmniAccessor.get(parent, "{Child}/{GrandChild}/content");
assertEquals(1, contents.size());
assertEquals("from child", contents.get(0));
// 使用带下标的路径读取成员对象
assertEquals("from 2nd children", OmniAccessor.getFirst(parent, "children[1]/{GrandChild}/content"));
assertEquals("from 3rd children", OmniAccessor.getFirst(parent, "{Child[]}[2]/{GrandChild}/content"));
// 使用模糊路径快速读取成员对象
assertEquals("from 1st children", OmniAccessor.getFirst(parent, "{C*[]}[0]/*/con*t"));
}
@Test
void should_set_any_member() {
Parent parent = OmniConstructor.newInstance(Parent.class);
parent.setChildren(OmniConstructor.newArray(Child.class, 3));
// 使用指定路径快速给成员对象赋值
OmniAccessor.set(parent, "child/grandChild/content", "demo child");
assertEquals("demo child", parent.getChild().getGrandChild().getContent());
// 使用带下标的路径给成员对象赋值
OmniAccessor.set(parent, "children[1]/grandChild/content", "demo children[1]");
assertEquals("demo children[1]", parent.getChildren()[1].getGrandChild().getContent());
// 使用模糊路径批量给成员对象赋值
OmniAccessor.set(parent, "child*/*/content", "demo in batch");
assertEquals("demo in batch", parent.getChild().getGrandChild().getContent());
assertEquals("demo in batch", parent.getChildren()[0].getGrandChild().getContent());
assertEquals("demo in batch", parent.getChildren()[1].getGrandChild().getContent());
assertEquals("demo in batch", parent.getChildren()[2].getGrandChild().getContent());
// 读写私有内部类类型的成员使用类型名引用内部类时无需带外部类名
assertEquals("", OmniAccessor.getFirst(parent, "subChild/secret"));
OmniAccessor.set(parent, "{InnerChild}/secret", "inner-class secret");
assertEquals("inner-class secret", OmniAccessor.getFirst(parent, "subChild/secret"));
}
}

View File

@ -1,78 +0,0 @@
package com.alibaba.demo.basic;
import com.alibaba.testable.core.accessor.PrivateAccessor;
import com.alibaba.demo.basic.DemoPrivateAccess;
import com.alibaba.testable.processor.annotation.EnablePrivateAccess;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* 演示私有成员访问功能
* Demonstrate private member access functionality
*/
@EnablePrivateAccess
class DemoPrivateAccessTest {
private DemoPrivateAccess demoPrivateAccess = new DemoPrivateAccess();
@Test
void should_able_to_access_private_method() {
List<String> list = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }};
assertEquals("member", demoPrivateAccess.privateFunc());
assertEquals("member", PrivateAccessor.invoke(demoPrivateAccess, "privateFunc"));
assertEquals("abc + hello + 1", demoPrivateAccess.privateFuncWithArgs(list, "hello", 1));
assertEquals("abc + hello + 1", PrivateAccessor.invoke(demoPrivateAccess, "privateFuncWithArgs", list, "hello", 1));
}
@Test
void should_able_to_access_private_field() {
demoPrivateAccess.count = 2;
assertEquals(Integer.valueOf(2), demoPrivateAccess.count);
PrivateAccessor.set(demoPrivateAccess, "count", 3);
assertEquals(Integer.valueOf(3), PrivateAccessor.get(demoPrivateAccess, "count"));
}
@Test
void should_able_to_access_private_static_method() {
assertEquals("static", DemoPrivateAccess.privateStaticFunc());
assertEquals("static", PrivateAccessor.invokeStatic(DemoPrivateAccess.class, "privateStaticFunc"));
assertEquals("hello + 1", DemoPrivateAccess.privateStaticFuncWithArgs("hello", 1));
assertEquals("hello + 1", PrivateAccessor.invokeStatic(DemoPrivateAccess.class, "privateStaticFuncWithArgs", "hello", 1));
}
@Test
void should_able_to_access_private_static_field() {
DemoPrivateAccess.staticCount = 2;
assertEquals(Integer.valueOf(2), DemoPrivateAccess.staticCount);
PrivateAccessor.setStatic(DemoPrivateAccess.class, "staticCount", 3);
assertEquals(Integer.valueOf(3), PrivateAccessor.getStatic(DemoPrivateAccess.class, "staticCount"));
}
@Test
void should_able_to_update_final_field() {
demoPrivateAccess.pi = 4.13;
assertEquals(Double.valueOf(4.13), demoPrivateAccess.pi);
PrivateAccessor.set(demoPrivateAccess, "pi", 3.14);
assertEquals(Double.valueOf(3.14), PrivateAccessor.get(demoPrivateAccess, "pi"));
}
@Test
void should_able_to_use_null_parameter() {
demoPrivateAccess.pi = null;
assertNull(demoPrivateAccess.pi);
assertEquals("null + 1", DemoPrivateAccess.privateStaticFuncWithArgs(null, 1));
PrivateAccessor.set(demoPrivateAccess, "pi", null);
assertNull(PrivateAccessor.get(demoPrivateAccess, "pi"));
assertEquals("null + 1", PrivateAccessor.invokeStatic(DemoPrivateAccess.class, "privateStaticFuncWithArgs", null, 1));
}
}

View File

@ -0,0 +1,64 @@
package com.alibaba.demo.basic;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.testable.core.tool.PrivateAccessor.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* 演示使用`PrivateAccessor`工具类访问私有成员
* Demonstrate access private member via `PrivateAccessor` class
*/
class DemoPrivateAccessorTest {
private DemoPrivateAccess demoPrivateAccess = new DemoPrivateAccess();
@Test
void should_access_private_method() {
List<String> list = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }};
assertEquals("member", invoke(demoPrivateAccess, "privateFunc"));
assertEquals("abc + hello + 1", invoke(demoPrivateAccess, "privateFuncWithArgs", list, "hello", 1));
}
@Test
void should_access_private_field() {
set(demoPrivateAccess, "count", 3);
assertEquals(Integer.valueOf(3), get(demoPrivateAccess, "count"));
}
@Test
void should_access_private_static_method() {
assertEquals("static", invokeStatic(DemoPrivateAccess.class, "privateStaticFunc"));
assertEquals("hello + 1", invokeStatic(DemoPrivateAccess.class, "privateStaticFuncWithArgs", "hello", 1));
}
@Test
void should_access_private_static_field() {
setStatic(DemoPrivateAccess.class, "staticCount", 3);
assertEquals(Integer.valueOf(3), getStatic(DemoPrivateAccess.class, "staticCount"));
}
@Test
void should_update_final_field() {
set(demoPrivateAccess, "pi", 3.14);
assertEquals(Double.valueOf(3.14), get(demoPrivateAccess, "pi"));
}
@Test
void should_use_null_parameter() {
set(demoPrivateAccess, "pi", null);
assertNull(get(demoPrivateAccess, "pi"));
List<String> list = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }};
String value = invoke(demoPrivateAccess, "privateFuncWithArgs", list, null, 0);
assertEquals("abc + null + 0", value);
value = invokeStatic(DemoPrivateAccess.class, "privateStaticFuncWithArgs", null, 1);
assertEquals("null + 1", value);
}
}

View File

@ -0,0 +1,59 @@
package com.alibaba.demo.basic;
import com.alibaba.testable.processor.annotation.EnablePrivateAccess;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* 演示使用`@EnablePrivateAccess`注解访问私有成员
* Demonstrate access private member via `@EnablePrivateAccess` annotation
*/
@EnablePrivateAccess(srcClass = DemoPrivateAccess.class)
class DemoPrivateProcessorTest {
private DemoPrivateAccess demoPrivateAccess = new DemoPrivateAccess();
@Test
void should_access_private_method() {
List<String> list = new ArrayList<String>() {{ add("a"); add("b"); add("c"); }};
assertEquals("member", demoPrivateAccess.privateFunc());
assertEquals("abc + hello + 1", demoPrivateAccess.privateFuncWithArgs(list, "hello", 1));
}
@Test
void should_access_private_field() {
demoPrivateAccess.count = 2;
assertEquals(Integer.valueOf(2), demoPrivateAccess.count);
}
@Test
void should_access_private_static_method() {
assertEquals("static", DemoPrivateAccess.privateStaticFunc());
assertEquals("hello + 1", DemoPrivateAccess.privateStaticFuncWithArgs("hello", 1));
}
@Test
void should_access_private_static_field() {
DemoPrivateAccess.staticCount = 2;
assertEquals(Integer.valueOf(2), DemoPrivateAccess.staticCount);
}
@Test
void should_update_final_field() {
demoPrivateAccess.pi = 4.13;
assertEquals(Double.valueOf(4.13), demoPrivateAccess.pi);
}
@Test
void should_use_null_parameter() {
demoPrivateAccess.pi = null;
assertNull(demoPrivateAccess.pi);
assertEquals("null + 1", DemoPrivateAccess.privateStaticFuncWithArgs(null, 1));
}
}

View File

@ -0,0 +1,115 @@
package com.alibaba.demo.basic;
import com.alibaba.demo.basic.model.mock.BlackBox;
import com.alibaba.demo.basic.model.mock.Box;
import com.alibaba.demo.basic.model.mock.Color;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* 演示父类变量引用子类对象时的Mock场景
* Demonstrate scenario of mocking method from sub-type object referred by parent-type variable
*/
class DemoReferenceTest {
private DemoReference demoReference = new DemoReference();
public static class Mock {
/**
* 当需要引用原对象时不加`targetClass`参数将原类型作为Mock方法的首个参数建议将参数命名为`self`
* When method body need to refer the invoked object, skip the use `targetClass` parameter,
* and add a parameter `self` with target class type before other paramter of the target method
*/
@MockInvoke(targetMethod = "put")
private void put_into_box(Box self, String something) {
self.put("put_" + something + "_into_box");
}
@MockInvoke(targetMethod = "put")
private void put_into_blackbox(BlackBox self, String something) {
self.put("put_" + something + "_into_blackbox");
}
/**
* 当不需要引用原对象时将目标类型作为`@MockInvoke`注解的`targetClass`参数值即可
* When the invoked object is not used in the mock method, set `targetClass` value to the type who owns the mocked method
*/
@MockInvoke(targetClass = Box.class, targetMethod = "get")
private String get_from_box() {
return "get_from_box";
}
@MockInvoke(targetClass = BlackBox.class, targetMethod = "get")
private String get_from_blackbox() {
return "get_from_blackbox";
}
@MockInvoke(targetClass = Color.class, targetMethod = "getColor")
private String get_color_from_color() {
return "color_from_color";
}
@MockInvoke(targetClass = BlackBox.class, targetMethod = "getColor")
private String get_color_from_blackbox() {
return "color_from_blackbox";
}
@MockInvoke(targetClass = Color.class, targetMethod = "getColorIndex")
private String get_colorIdx_from_color() {
return "colorIdx_from_color";
}
}
@Test
void should_mock_call_sub_object_method_by_parent_object() {
BlackBox box = (BlackBox) demoReference.putIntoBox();
verifyInvoked("put_into_box").withTimes(1);
assertEquals("put_data_into_box", box.get());
}
@Test
void should_mock_call_sub_object_method_by_sub_object() {
BlackBox box = demoReference.putIntoBlackBox();
verifyInvoked("put_into_blackbox").withTimes(1);
assertEquals("put_data_into_blackbox", box.get());
}
@Test
void should_mock_call_parent_object_method_by_parent_object() {
String content = demoReference.getFromBox();
verifyInvoked("get_from_box").withTimes(1);
assertEquals("get_from_box", content);
}
@Test
void should_mock_call_parent_object_method_by_sub_object() {
String content = demoReference.getFromBlackBox();
verifyInvoked("get_from_blackbox").withTimes(1);
assertEquals("get_from_blackbox", content);
}
@Test
void should_mock_call_interface_method_by_interface_object() {
String color = demoReference.getColorViaColor();
verifyInvoked("get_color_from_color").withTimes(1);
assertEquals("color_from_color", color);
}
@Test
void should_mock_call_interface_method_by_sub_class_object() {
String color = demoReference.getColorViaBox();
verifyInvoked("get_color_from_blackbox").withTimes(1);
assertEquals("color_from_blackbox", color);
}
@Test
void should_mock_call_interface_method_by_sub_interface_object() {
String colorIdx = demoReference.getColorIdxViaColor();
verifyInvoked("get_colorIdx_from_color").withTimes(1);
assertEquals("colorIdx_from_color", colorIdx);
}
}

View File

@ -1,8 +1,7 @@
package com.alibaba.demo.basic; package com.alibaba.demo.basic;
import com.alibaba.testable.core.annotation.MockConstructor; import com.alibaba.testable.core.annotation.MockNew;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
import com.alibaba.demo.basic.DemoTemplate;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.*; import java.util.*;
@ -21,24 +20,24 @@ class DemoTemplateTest {
/* 第一种写法:使用泛型定义 */ /* 第一种写法:使用泛型定义 */
/* First solution: use generics type */ /* First solution: use generics type */
@MockMethod @MockInvoke
private <T> List<T> getList(DemoTemplate self, T value) { private <T> List<T> getList(DemoTemplate self, T value) {
return new ArrayList<T>() {{ add((T)(value.toString() + "_mock_list")); }}; return new ArrayList<T>() {{ add((T)(value.toString() + "_mock_list")); }};
} }
@MockMethod @MockInvoke
private <K, V> Map<K, V> getMap(DemoTemplate self, K key, V value) { private <K, V> Map<K, V> getMap(DemoTemplate self, K key, V value) {
return new HashMap<K, V>() {{ put(key, (V)(value.toString() + "_mock_map")); }}; return new HashMap<K, V>() {{ put(key, (V)(value.toString() + "_mock_map")); }};
} }
@MockConstructor @MockNew
private <T> HashSet<T> newHashSet() { private <T> HashSet<T> newHashSet() {
HashSet<T> set = new HashSet<>(); HashSet<T> set = new HashSet<>();
set.add((T)"insert_mock"); set.add((T)"insert_mock");
return set; return set;
} }
@MockMethod @MockInvoke
private <E> boolean add(Set s, E e) { private <E> boolean add(Set s, E e) {
s.add(e.toString() + "_mocked"); s.add(e.toString() + "_mocked");
return true; return true;
@ -47,24 +46,24 @@ class DemoTemplateTest {
/* 第二种写法使用Object类型 */ /* 第二种写法使用Object类型 */
/* Second solution: use object type */ /* Second solution: use object type */
//@MockMethod //@MockInvoke
//private List<Object> getList(DemoTemplate self, Object value) { //private List<Object> getList(DemoTemplate self, Object value) {
// return new ArrayList<Object>() {{ add(value.toString() + "_mock_list"); }}; // return new ArrayList<Object>() {{ add(value.toString() + "_mock_list"); }};
//} //}
// //
//@MockMethod //@MockInvoke
//private Map<Object, Object> getMap(DemoTemplate self, Object key, Object value) { //private Map<Object, Object> getMap(DemoTemplate self, Object key, Object value) {
// return new HashMap<Object, Object>() {{ put(key, value.toString() + "_mock_map"); }}; // return new HashMap<Object, Object>() {{ put(key, value.toString() + "_mock_map"); }};
//} //}
// //
//@MockConstructor //@MockNew
//private HashSet newHashSet() { //private HashSet newHashSet() {
// HashSet<Object> set = new HashSet<>(); // HashSet<Object> set = new HashSet<>();
// set.add("insert_mock"); // set.add("insert_mock");
// return set; // return set;
//} //}
// //
//@MockMethod //@MockInvoke
//private boolean add(Set s, Object e) { //private boolean add(Set s, Object e) {
// s.add(e.toString() + "_mocked"); // s.add(e.toString() + "_mocked");
// return true; // return true;
@ -72,19 +71,19 @@ class DemoTemplateTest {
} }
@Test @Test
void should_able_to_mock_single_template_method() { void should_mock_single_template_method() {
String res = demoTemplate.singleTemplateMethod(); String res = demoTemplate.singleTemplateMethod();
assertEquals("demo_mock_list", res); assertEquals("demo_mock_list", res);
} }
@Test @Test
void should_able_to_mock_double_template_method() { void should_mock_double_template_method() {
String res = demoTemplate.doubleTemplateMethod(); String res = demoTemplate.doubleTemplateMethod();
assertEquals("testable_mock_map", res); assertEquals("testable_mock_map", res);
} }
@Test @Test
void should_able_to_mock_new_template_method() { void should_mock_new_template_method() {
Set<?> res = demoTemplate.newTemplateMethod(); Set<?> res = demoTemplate.newTemplateMethod();
assertEquals(2, res.size()); assertEquals(2, res.size());
Iterator<?> iterator = res.stream().iterator(); Iterator<?> iterator = res.stream().iterator();

View File

@ -0,0 +1,48 @@
package com.alibaba.demo.inherit;
import com.alibaba.testable.core.annotation.MockContainer;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.*;
/**
* 演示使用@MockContainer注解实现Mock容器类的多重继承
* Demonstrate multiple inherit of mock container class with @MockContainer annotation
*/
class DemoMultipleInheritTest {
private DemoMultipleInherit demoMultipleInherit = new DemoMultipleInherit();
public static class PrefixMock {
@MockInvoke(targetClass = DemoMultipleInherit.class)
private String prefix() {
return "in_";
}
}
public static class SuffixMock {
@MockInvoke(targetClass = DemoMultipleInherit.class)
private String suffix(int some, String more, Object[] parameters) {
return "_it";
}
}
@MockContainer(inherits = { PrefixMock.class, SuffixMock.class })
public static class Mock {
@MockInvoke(targetClass = DemoMultipleInherit.class)
private String middle() {
return "her";
}
}
@Test
public void should_use_mock_method_in_parent_class() {
assertEquals("in_her_it", demoMultipleInherit.entry());
verifyInvoked("prefix").withTimes(1);
verifyInvoked("middle").withTimes(1);
verifyInvoked("suffix").withTimes(1);
}
}

View File

@ -0,0 +1,38 @@
package com.alibaba.demo.inherit;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* 演示Mock容器类的继承
* Demonstrate inherit of mock container class with extends keyword
*/
class DemoSingleInheritTest {
private DemoSingleInherit demoSingleInherit = new DemoSingleInherit();
public static class BasicMock {
@MockInvoke(targetClass = DemoSingleInherit.class)
private String suffix() {
return "_ck";
}
}
public static class Mock extends BasicMock {
@MockInvoke(targetClass = DemoSingleInherit.class)
private String prefix() {
return "mo_";
}
}
@Test
public void should_use_mock_method_in_parent_class() {
assertEquals("mo_test_ck", demoSingleInherit.entry("test"));
verifyInvoked("prefix").withTimes(1);
verifyInvoked("suffix").withTimes(1);
}
}

View File

@ -0,0 +1,25 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
/**
* @author jim
*/
public class CollectionListCodeDemoTest {
private final CollectionListCodeDemo instance = new CollectionListCodeDemo();
public static class Mock {
@MockInvoke(targetClass = String.class, targetMethod = "contains")
public boolean mockContains(CharSequence s) {
return false;
}
}
@Test
public void listTest() {
instance.list();
}
}

View File

@ -0,0 +1,69 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
/**
* @author jim
*/
public class InvokeInterfaceDemoTest {
private final InvokeInterfaceDemo instance = new InvokeInterfaceDemo();
public static class Mock {
@MockInvoke(targetClass = InvokeInterfaceDemo.ILambda.class, targetMethod = "run")
private void mockILambdaRun() {
}
@MockInvoke(targetClass = InvokeInterfaceDemo.ILambda.class, targetMethod = "function1")
private void mockILambdaFunction1(String s) {
}
@SuppressWarnings("unchecked")
@MockInvoke(targetClass = Collection.class, targetMethod = "stream")
<E> Stream<E> mockStream() {
List<E> fooList = new ArrayList<>();
fooList.add((E) "123");
fooList.add((E) "456");
return fooList.stream();
}
@MockInvoke(targetClass = Boolean.class, targetMethod = "logicalAnd")
public static boolean mockLogicalAnd(boolean a, boolean b) {
return false;
}
}
@Test
public void shouldMockCollectionStream() {
instance.collectionInterfaceDefaultOrStatic();
verifyInvoked("mockStream").withTimes(1);
}
@Test
public void shouldMockInterfaceDefault() {
instance.interfaceDefault();
verifyInvoked("mockILambdaRun").withTimes(1);
verifyInvoked("mockILambdaFunction1").withTimes(1);
}
@Test
public void shouldMockObjectStaticMethodReference() {
instance.objectStaticMethodReference();
verifyInvoked("mockLogicalAnd").withTimes(2);
}
@Test
public void shouldMockInterfaceStatic() {
instance.interfaceStatic();
}
}

View File

@ -0,0 +1,80 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
/**
* @author zcbbpo
*/
public class InvokeVirtualDemoTest {
private final InvokeVirtualDemo lambdaDemo = new InvokeVirtualDemo();
@SuppressWarnings("unused")
public static class Mock {
@MockInvoke(targetClass = String.class, targetMethod = "contains")
public boolean mockContains(CharSequence s) {
return false;
}
@MockInvoke(targetClass = Byte.class, targetMethod = "floatValue")
public float mockFloatValue() {
return 0.1f;
}
@MockInvoke(targetClass = Double.class, targetMethod = "compareTo")
public int mockCompareTo(Double anotherDouble) {
return 1;
}
@MockInvoke(targetClass = LambdaDemo.class, targetMethod = "methodReference0")
public String mockMethodReference0() {
return "";
}
@MockInvoke(targetClass = InvokeVirtualDemo.class, targetMethod = "f3")
public Boolean mockF3(String s1, Long l) {
return true;
}
}
@Test
public void shouldMockString1() {
lambdaDemo.string1();
verifyInvoked("mockContains").withTimes(1);
}
@Test
public void shouldMockByte1() {
lambdaDemo.byte1();
verifyInvoked("mockFloatValue").withTimes(1);
}
@Test
public void shouldMockDouble2() {
lambdaDemo.double2();
verifyInvoked("mockCompareTo").withTimes(1);
}
@Test
public void testMul() {
lambdaDemo.mul();
verifyInvoked("mockContains").withTimes(2);
}
@Test
public void testExternalClass() {
lambdaDemo.externalClass();
verifyInvoked("mockMethodReference0").withTimes(1);
}
@Test
public void testFunction3() {
lambdaDemo.function3();
verifyInvoked("mockF3").withTimes(1);
}
}

View File

@ -0,0 +1,86 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author zcbbpo
*/
public class LambdaDemoTest {
private final LambdaDemo lambdaDemo = new LambdaDemo();
@SuppressWarnings("unused")
public static class Mock {
@MockInvoke(targetClass = LambdaDemo.class, targetMethod = "run")
private void mockRun() {
}
@MockInvoke(targetClass = LambdaDemo.class)
private String function0() {
return "mock_function0";
}
@MockInvoke(targetClass = LambdaDemo.class)
private String function1(Integer i) {
return "mock_function1";
}
@MockInvoke(targetClass = LambdaDemo.class)
private String function2(Integer i, Double d) {
return "mock_function2";
}
@SuppressWarnings("RedundantThrows")
@MockInvoke(targetClass = LambdaDemo.class)
private String function1Throwable(Integer i) throws Throwable{
return "mock_function1Throwable";
}
@MockInvoke(targetClass = StaticMethod.class, targetMethod = "function1")
public static String staticFunction1(Integer i) {
return "mock_staticFunction1";
}
}
@Test
public void shouldMockRun() {
lambdaDemo.methodReference();
verifyInvoked("mockRun").withTimes(1);
}
@Test
public void shouldMockFunction0() {
String s = lambdaDemo.methodReference0();
assertEquals(s, "mock_function0");
}
@Test
public void shouldMockFunction1() {
String s = lambdaDemo.methodReference1();
assertEquals(s, "mock_function1");
}
@Test
public void shouldMockFunction2() {
String s = lambdaDemo.methodReference2();
assertEquals(s, "mock_function2");
}
@Test
public void shouldMockFunction1Throws() {
String s = lambdaDemo.methodReferenceThrows();
assertEquals(s, "mock_function1Throwable");
}
@Test
public void shouldMockStaticFunction1() {
String s = lambdaDemo.staticMethodReference1();
assertEquals(s, "mock_staticFunction1");
}
}

View File

@ -0,0 +1,33 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockInvoke;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
/**
* @author jim
*/
public class StaticInstanceReferenceTest {
private final StaticInstanceReference instance = new StaticInstanceReference();
public static class Mock {
@MockInvoke(targetClass = StaticInstanceReference.StaticClassA.class, targetMethod = "doIt")
private void mockDoIt() {
}
@MockInvoke(targetClass = StaticInstanceReference.StaticClassA.class)
private Integer function2(String s) {
return 2;
}
}
@Test
public void shouldMockDoIt() {
instance.staticMethodReference();
verifyInvoked("mockDoIt").withTimes(1);
verifyInvoked("function2").withTimes(1);
}
}

View File

@ -1,10 +1,10 @@
package com.alibaba.demo.one2multi; package com.alibaba.demo.one2multi;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
public class ASvcMock { public class ASvcMock {
@MockMethod(targetClass = String.class, targetMethod = "format") @MockInvoke(targetClass = String.class, targetMethod = "format")
public String a_format(String format, Object... args) { public String a_format(String format, Object... args) {
return "a_mock"; return "a_mock";
} }

View File

@ -1,10 +1,10 @@
package com.alibaba.demo.one2multi; package com.alibaba.demo.one2multi;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
public class BSvcMock { public class BSvcMock {
@MockMethod(targetClass = String.class, targetMethod = "format") @MockInvoke(targetClass = String.class, targetMethod = "format")
public String b_format(String format, Object... args) { public String b_format(String format, Object... args) {
return "b_mock"; return "b_mock";
} }

View File

@ -1,10 +1,10 @@
package com.alibaba.demo.one2multi; package com.alibaba.demo.one2multi;
import com.alibaba.testable.core.annotation.MockMethod; import com.alibaba.testable.core.annotation.MockInvoke;
public class CSvcMock { public class CSvcMock {
@MockMethod(targetClass = String.class, targetMethod = "format") @MockInvoke(targetClass = String.class, targetMethod = "format")
public String c_format(String format, Object... args) { public String c_format(String format, Object... args) {
return "c_mock"; return "c_mock";
} }

View File

@ -4,7 +4,7 @@ import com.alibaba.testable.core.annotation.MockWith;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvokeVerifier.verify; import static com.alibaba.testable.core.matcher.InvocationVerifier.verifyInvoked;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@MockWith @MockWith
@ -15,13 +15,13 @@ public class OneToMultiSvcTest {
private CSvc cSvc = new CSvc(); private CSvc cSvc = new CSvc();
@Test @Test
public void should_able_to_test_multi_class_together() { public void should_test_multi_class_together() {
assertEquals("a_mock", aSvc.demo("test")); assertEquals("a_mock", aSvc.demo("test"));
assertEquals("b_mock", bSvc.demo("test")); assertEquals("b_mock", bSvc.demo("test"));
assertEquals("c_mock", cSvc.demo("test")); assertEquals("c_mock", cSvc.demo("test"));
verify("a_format").withTimes(1); verifyInvoked("a_format").withTimes(1);
verify("b_format").withTimes(1); verifyInvoked("b_format").withTimes(1);
verify("c_format").withTimes(1); verifyInvoked("c_format").withTimes(1);
} }
} }

View File

@ -0,0 +1,2 @@
omni.constructor.enhance.enable = true
mock.target.checking.enable = true

View File

@ -9,6 +9,7 @@ version = "1.0.0-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8 java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
} }
@ -16,8 +17,8 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
testImplementation("com.alibaba.testable:testable-all:0.5.2") testImplementation("com.alibaba.testable:testable-all:0.7.9")
testAnnotationProcessor("com.alibaba.testable:testable-processor:0.5.2") testAnnotationProcessor("com.alibaba.testable:testable-processor:0.7.9")
} }
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {

View File

@ -13,8 +13,8 @@
<kotlin.version>1.3.72</kotlin.version> <kotlin.version>1.3.72</kotlin.version>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<junit.version>5.6.2</junit.version> <junit.version>5.9.1</junit.version>
<testable.version>0.5.2</testable.version> <testable.version>0.7.9</testable.version>
</properties> </properties>
<dependencies> <dependencies>
@ -50,7 +50,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.0.0-M7</version>
<!-- <configuration>--> <!-- <configuration>-->
<!-- <argLine>@{argLine} -javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine>--> <!-- <argLine>@{argLine} -javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine>-->
<!-- </configuration>--> <!-- </configuration>-->
@ -71,7 +71,7 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version> <version>0.8.8</version>
<executions> <executions>
<execution> <execution>
<id>prepare-agent</id> <id>prepare-agent</id>

View File

@ -1 +0,0 @@
rootProject.name = "demo"

View File

@ -0,0 +1,34 @@
package com.alibaba.demo.association
/**
* 目标类此类中的一些调用将会被Mock掉
* Target class, some invocations inside this class will be mocked
*/
class CookerService {
private fun cookSandwich(): String {
return "Real-Sandwich"
}
private fun cookHamburger(): String {
return "Real-Hamburger"
}
fun prepareSandwich(): String {
return hireSandwichCooker() + " & " + cookSandwich()
}
fun prepareHamburger(): String {
return hireHamburgerCooker() + " & " + cookHamburger()
}
companion object {
private fun hireSandwichCooker(): String {
return "Real-Sandwich-Cooker"
}
private fun hireHamburgerCooker(): String {
return "Real-Hamburger-Cooker"
}
}
}

View File

@ -0,0 +1,18 @@
package com.alibaba.demo.association
/**
* 被测类会访问`CookerService`里的方法
* Class to be tested, which will access methods in TargetService class
*/
class SellerService {
private val cookerService = CookerService()
fun sellSandwich(): String {
return cookerService.prepareSandwich()
}
fun sellHamburger(): String {
return cookerService.prepareHamburger()
}
}

View File

@ -1,6 +1,6 @@
package com.alibaba.demo.basic package com.alibaba.demo.basic
import com.alibaba.demo.basic.model.BlackBox import com.alibaba.demo.basic.model.mock.BlackBox
import java.util.* import java.util.*
/** /**

View File

@ -1,7 +1,7 @@
package com.alibaba.demo.basic package com.alibaba.demo.basic
import com.alibaba.demo.basic.model.BlackBox import com.alibaba.demo.basic.model.mock.BlackBox
import com.alibaba.demo.basic.model.ColorBox import com.alibaba.demo.basic.model.mock.ColorBox
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths

View File

@ -9,7 +9,7 @@ class DemoPrivateAccess {
/** /**
* a private member field * a private member field
*/ */
private var count = 0 var count = 0
/** /**
* a constant field * a constant field
@ -19,7 +19,7 @@ class DemoPrivateAccess {
/** /**
* private member method * private member method
*/ */
private fun privateFunc(list: List<String>, str: String, i: Int): String { fun privateFunc(list: List<String>, str: String, i: Int): String {
return list.reduce { a: String, s: String -> a + s } + " + " + "$str + $i" return list.reduce { a: String, s: String -> a + s } + " + " + "$str + $i"
} }
@ -28,12 +28,12 @@ class DemoPrivateAccess {
/** /**
* a private static field * a private static field
*/ */
private var staticCount = 0 var staticCount = 0
/** /**
* private static method * private static method
*/ */
private fun privateStaticFunc(str: String, i: Int): String { fun privateStaticFunc(str: String, i: Int): String {
return "$str + $i" return "$str + $i"
} }

View File

@ -1,17 +1,17 @@
package com.alibaba.demo.basic package com.alibaba.demo.basic
import com.alibaba.demo.basic.model.BlackBox import com.alibaba.demo.basic.model.mock.BlackBox
import com.alibaba.demo.basic.model.Box import com.alibaba.demo.basic.model.mock.Box
import com.alibaba.demo.basic.model.Color import com.alibaba.demo.basic.model.mock.Color
/** /**
* 演示父类变量引用子类对象时的Mock场景 * 演示父类变量引用子类对象时的Mock场景
* Demonstrate scenario of mocking method from sub-type object referred by parent-type variable * Demonstrate scenario of mocking method from sub-type object referred by parent-type variable
*/ */
class DemoInherit { class DemoReference {
/** /**
* call method overridden by sub class via parent class variable * call method overridden by subclass via parent class variable
*/ */
fun putIntoBox(): Box { fun putIntoBox(): Box {
val box: Box = BlackBox("") val box: Box = BlackBox("")
@ -20,7 +20,7 @@ class DemoInherit {
} }
/** /**
* call method overridden by sub class via sub class variable * call method overridden by subclass via subclass variable
*/ */
fun putIntoBlackBox(): BlackBox { fun putIntoBlackBox(): BlackBox {
val box = BlackBox("") val box = BlackBox("")
@ -38,7 +38,7 @@ class DemoInherit {
} }
/** /**
* call method defined in parent class via sub class variable * call method defined in parent class via subclass variable
*/ */
val fromBlackBox: String? val fromBlackBox: String?
get() { get() {
@ -56,7 +56,7 @@ class DemoInherit {
} }
/** /**
* call method defined in interface via sub class variable * call method defined in interface via subclass variable
*/ */
val colorViaBox: String val colorViaBox: String
get() { get() {

View File

@ -1,4 +1,4 @@
package com.alibaba.demo.basic.model package com.alibaba.demo.basic.model.mock
class BlackBox(var input: String) : Box(), Color { class BlackBox(var input: String) : Box(), Color {

Some files were not shown because too many files have changed in this diff Show More