google-developer-training / advanced-android-testing Goto Github PK
View Code? Open in Web Editor NEWAndroid Testing Codelab
Home Page: https://codelabs.developers.google.com/codelabs/android-testing/
License: Apache License 2.0
Android Testing Codelab
Home Page: https://codelabs.developers.google.com/codelabs/android-testing/
License: Apache License 2.0
Step 5 MVP In Practice mentions
Now temporarily comment out the mActionsListener field. This will show us where (and how) we make calls to the Presenter:
NotesFragment.java
// private NotesContract.UserActionsListener mActionsListener;
But when I open this file in a fresh clone of branch step-1-5 it's already uncommented.
Hi,
In the lesson 5 MVP in practice, following code is shown to be in onActivityCreated
but it is actually in .onCreate`.
mActionsListener = new NotesPresenter(Injection.provideNotesRepository(), this);
Code in concern- https://github.com/googlecodelabs/android-testing/blob/master/app/src/main/java/com/example/android/testing/notes/notes/NotesFragment.java#L79
In Step 9, the "Espresso-Contrib" section, there are two subheadings for the test cases sections labelled "Espresso-Intents Test #". As this is the "Espresso-Contrib" section, the subheadings should be "Espresso-Contrib Test #".
Did you know that unit tests should make up to 70% of your tests?
I believe that a statement like this is useless without further explanation or a link to more information. You could point readers to the article Just Say No to More End-to-End Tests.
there is a line that says:
First we capture the callback in the captor, then we call it with an empty list of notes:
which is referring to this code:
mLoadNotesCallbackCaptor.getValue().onNotesLoaded(NOTES);
However NOTES
is not an empty list. So either use the EMPTY_NOTES
field in the code or change the description so that it refers to a list of notes rather than empty list of notes.
Line: 124 - Getting an error that scrollTo doesn't work with a Matcher as a parameter
duplication of text. A sentence is repeated twice in a row.
If you would like to start fresh for this section, continue from snapshot ‘step-7’:If you would like to start fresh for this section, continue from snapshot ‘step-7’:
Cloning this and opening in Android Studio 1.5.1 I get the following error:
Error:(35, 0) No signature of method: java.lang.String.variantFilter() is applicable for argument types: (build_8svktq4s2wa741jcavj9ayd99$_run_closure1_closure8) values: [build_8svktq4s2wa741jcavj9ayd99$_run_closure1_closure8@191ee85a]
This refers to the app/build.gradle
line
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
if(variant.buildType.name.equals('release')
&& variant.getFlavors().get(0).name.equals('mock')) {
variant.setIgnore(true);
}
}
I tried changing android.variantFilter
to applicationVariants.all
which then moved the problem to getFlavors()
.
Am I using the wrong version of gradle?
https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex#4
In the section Creating the NotesPresenter
The NotesPresenter object is created in onCreate(...)
instead of onActivityCreated(...)
Thank you.
At the section that shows the pass fail of the clickOnAndroidHomeIcon_OpensNavigation test, the image shows the clickOnAndroidHomeIcon_OpensNavigation failing and the clickOnStatisticsNavigationItem_ShowsStatisticsScreen test passing. Shouldn't it be the other way around?
That's in the title
I'm following the tutorial
https://codelabs.developers.google.com/codelabs/android-testing/index.html
I see that in step 5 it's mentioned
https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex#4
If you have run the app already, you will have noticed that we are getting a blank screen with no notes or working buttons!
Please move this information to step 2.
IMHO the usage of @rule public MockitoRule rule = MockitoJUnit.rule(); is much nicer, compared to MockitoAnnotations.initMocks(this);
You should update your NotesPresenterTest
On master branch executing
./gradlew createMockDebugCoverageReport
produces the following
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Landroid/support/design/R$anim;
at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:596)
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:554)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:535)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:171)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:189)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:502)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:334)
at com.android.dx.command.dexer.Main.run(Main.java:277)
at com.android.dx.command.dexer.Main.main(Main.java:245)
at com.android.dx.command.Main.main(Main.java:106)
Btw..Great codelab! Thanks for sharing.
https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex#5
In the section Mocking dependencies with Mockito
The link for the ArgumentCaptor
documentation is broken.
Thank you.
https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=../../index#6
The 7th step has typo
Launch NoteDetailActivity with an Intent extra parameter
Edit the file app/src/androidTestMock/java/.../notes/NoteDetailScreenTest.java
and comment in the method as you work through this section:
should be
Launch NoteDetailActivity with an Intent extra parameter
Edit the file app/src/androidTestMock/java/.../notedetail/NoteDetailScreenTest.java
and comment in the method as you work through this section:
I just run code with the doc in Section of Espresso Test 2: Adding a note
in Nexus 5 (API 23). Here is the logcat:
android.support.test.espresso.PerformException: Error performing 'scroll RecyclerView to: holder with view: has descendant: with text: is "UI testing for Android"' on view 'with id: com.example.android.testing.notes.mock:id/notes_list'.
at android.support.test.espresso.PerformException$Builder.build(PerformException.java:83)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:70)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
at com.example.android.testing.notes.notes.NotesScreenTest.addNoteToNotesList(NotesScreenTest.java:123)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:257)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)
Caused by: java.lang.RuntimeException: Found 0 items matching holder with view: has descendant: with text: is "UI testing for Android", but position -1 was requested.
at android.support.test.espresso.contrib.RecyclerViewActions$ScrollToViewAction.perform(RecyclerViewActions.java:357)
at android.support.test.espresso.ViewInteraction$1.run(ViewInteraction.java:144)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Thanks for fix it.
The following text is duplicated right at the beginning of Chapter 7, 8 and 9:
If you would like to start fresh for this section, continue from snapshot ‘step-7/8/9’:
Hi All,
Thanks very much for setting up this codelab for testing. It is great! One note - this was new to me. The files in the zip file at the codelab download web page - when unpacked on a Windows 7 system - show as encrypted. The zip file was downloaded from here:
https://codelabs.developers.google.com/codelabs/android-testing/#1
Some filenames show in a green color in Windows Explorer, indicating that they are encrypted. Evidently this is some interesting interaction where files encrypted on a Mac OS system are tagged with a bit that is confused by Windows as needing encryption. My solution - I will switch to pulling the files for the code lab from github. You can right click to Properties -> Advanced to clear the encryption status, but that is a hassle. :-)
Here is more info on the interesting interaction issue:
Since the Android Studio update yesterday (I think?), above error message happens when the code syncs.
In the step "Bonus: Code Coverage" the latest Android Studio version (2.1.1) is quite different from what is discussed in:
https://codelabs.developers.google.com/codelabs/android-testing/#10
After some fumbling around I found the code coverage controls and am now happily experimenting with them. There does seem to be some documentation here that matches what I see in Android Studio:
https://www.jetbrains.com/help/idea/2016.1/viewing-code-coverage-results.html
Basically a right click on the tests in the Project view provides a "Run soAndSo with Coverage" while mysteriously this is sometimes greyed out in the Run menubar drop-down. The "Coverage" side tab or View then Tool Windows then Coverage selection gives you the Coverage view of the underlying code. And the various packages are then annoted in the Project window with the percentage of test coverage. Rather nice!!
There are a few references to NoteDetailsScreenTest
that should be replaced with NoteDetailScreenTest
.
In section 7 there is:
Their status is displayed in the Run Panel that opened at the bottom of the screen:
and there is an image https://codelabs.developers.google.com/codelabs/android-testing/img/391e5d4c2d01e584.png where clickAddNoteButton_opensAddNoteUi
is green but I think at this step it should be red (it's on my machine) so the image is misleading.
When running the test at:
Step 7 - Running Espresso tests
I see the test fail when testing using emulators at Android versions 22 and 23. It succeeds at version 19.
There is something about the presence of the soft keyboard that interferes with the click function - adding a click (commented out below) didn't help. The workaround is to close the soft keyboard after the first typeText operation. This is shown (commented out) below.
public void addNoteToNotesList() throws Exception {
[...]
// Add note title and description
onView(withId(R.id.add_note_title)).perform(typeText(newNoteTitle) /* ,
closeSoftKeyboard() */ ); // Type new note title
// onView(withId(R.id.add_note_description)).perform(click());
onView(withId(R.id.add_note_description)).perform(typeText(newNoteDescription),
closeSoftKeyboard()); // Type new note description and close the keyboard
The error thrown is:
Error performing 'single click' on view 'with id: com.example.android.testing.notes:id/add_note_description'
I never understand how you can publish a codelab that builds just fine however the Espresso test have all types of build errors that are related to support libraries v4 and v7. When will you fix this nonsense and why don't you keep up with this stuff after it's published.
In step 6 there is a section 'Optionally sync your project'. With this section there is a line of text showing the button to sync Gradle.
This button icon has changed in Android Studio 2.2 so it might be worth showing both icons.
In Unit test Test Artifact, class NotesPresenterTest , loadNotesFromRepositoryAndLoadIntoView testcase:
verify(mNotesView).setProgressIndicator(false);
when flipping false to true, it still passing the test ! even it get called from presenter with false!
to validate that do the following,
verify(mNotesView).setProgressIndicator(false);
verify(mNotesView).setProgressIndicator(true);
verify(mNotesView).setProgressIndicator(false);
it still pass!, not sure where is the bug!
I have followed this tutorial series from beginning to the end . I have written this app step by step as I was learning to know how Testing works . every thing was just expected , but some of my instrument tests are showing this error . I have tested those test methods from the "android-testing" repo but those works fine . Can anyone tell What I am doing wrong ???
After updating the support library version from 23.1.1 to 23.3.0, the project breaks from a change to the CoordinatorLayout requirements. The FAB (floating action button) can no longer be anchored to the Coordinator Layout, but instead must be anchored to the contained FrameLayout. This needs to be changed in the activity_addnote.xml and activity_notes.xml files:
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
...
<FrameLayout
android:id="@+id/contentFrame"
...
<android.support.design.widget.FloatingActionButton
(***CHANGE HERE from coordinatorLayout to contentFrame)
app:layout_anchor="@id/contentFrame"
Here is a stackoverflow answer that provides this guidance.
I'm sorry for opening an issue but i dont know where else i can ask a question:
In the AddNotePresentar constructor there is this line:
addNoteView.setUserActionListener(this); (line 49)
Isn't this redundant because the constructor already set the mActionListener in the AddNoteFragment (line 79) or is there some usecase that i'm not following with that listener?
Cheers
Link to https://github.com/googlecodelabs/android-testing/blob/master/app/src/androidTest/java/com/example/android/testing/notes/custom/action/NavigationViewActions.java is broken, probably because NavigationViewActions is now part of espresso-contrib, no longer part of Notes.
Running errorShownOnEmptyMessage
test I always get android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with text: is "Notes cannot be empty"
exception.
These are my dependencies:
ext {
// Sdk and tools
minSdkVersion = 19
targetSdkVersion = 26
compileSdkVersion = 26
buildToolsVersion = '26.0.1'
// App dependencies
supportLibraryVersion = '26.1.0'
guavaVersion = '20.0'
glideVersion = '3.6.1'
junitVersion = '4.12'
mockitoVersion = '1.10.19'
powerMockito = '1.6.2'
hamcrestVersion = '1.3'
runnerVersion = '1.0.1'
rulesVersion = '1.0.1'
espressoVersion = '3.0.1'
}
I also replaced deprecated registering / unregistering methods for Idling Resources:
@Before public void registerIdlingResource() {
IdlingRegistry.getInstance()
.register(mAddNoteIntentsTestRule.getActivity().getCountingIdlingResource());
}
@After public void unregisterIdlingResource() {
IdlingRegistry.getInstance()
.unregister(mAddNoteIntentsTestRule.getActivity().getCountingIdlingResource());
}
I'm following the tutorial https://codelabs.developers.google.com/codelabs/android-testing/index.html. I've cloned the repo, imported code to Android Studio, run 'app' and ... it does not work (it starts but add note button does nothing).
I realized that Android Studio built the mockDebug version while it should build prodDebug.
Not an issue with the code but I don't know where else to put this. There are a lot of run-on sentences in the tutorial text that make it hard to follow the tutorial at times.
Examples:
Our repository here is only a mock object (and doesn't have any actual functionality), we need to fake the callback on the listener ourselves.
By default, all calls to the provided Android.jar throw exceptions, this allows you to write tests that do not depend on any Android platform behavior.
Android Testing Codelab Step 8: Bonus: Espresso-Intents
says androidTestMock/.../AddNoteScreenTest.java
@Rule
public IntentsTestRule<NotesActivity> mNotesIntentsTestRule = new IntentsTestRule<>(NotesActivity.class);
actually the Activity class under test should be AddNoteActivity
I'm sorry for creating an issue here maybe it was better to ask it on SO but I hope the creators of project or someone else answers my questions.
I've just become familiar with MVP pattern in android architecture, and packaging your classes over features instead of super classes.
Right now I use event driven architecture (Eventbus) in one of my apps. I was thinking what would be the benefit of using MVP over Event driven.
Using Eventbus I can seperate responsibilty of your methods very easily, So why would one migrate to MVP?
The other question is cant someone please overview the feasibility of using both MVP pattern and Event driven architecture?
The second question is the part you suggest using Dagger for mocking and stubbing, I see that's completely possible using a DI framework. but there's already mocking frameworks like mockito to mock your objects in test code instead of the source code, why should I use dagger in that sense?
In the following paragraph :
In our app we have wrapped the calls to Simple CountingIdlingResource...
I believe that we should have only one link redirection by concatenating the 2 words to be :
In our app we have wrapped the calls to SimpleCountingIdlingResource...
I have forked this project and created a new branch using dagger2.
See here
https://github.com/cpeppas/android-testing/tree/dagger
I thought this might be useful because dagger2 is becoming very popular nowadays.
Because of the fact that I cannot do a PL of a new branch that does not exist on the original project that's why I am raising this as an issue
Let me know if you think it is somehow valuable so I can do a PL in some way.
I am hitting this error at the following codelab step:
Espresso test 3: Clicking a note
The Android studio setup is shown in the snips below on Windows 7. I have not found a solution for this problem. It appears that the use of the "AndroidTestMock" facility is not in wide use - and so there is little to be found out there for guidance. Hmm.
Process finished with exit code 1
Class not found: "com.example.android.testing.notes.notedetail.NoteDetailScreenTest"Empty test suite.
in notesPresenterTest,java in the method loadNotesFromRepositoryAndLoadIntoView() i changed the value for
verify(mNotesView).setProgressIndicator(false);
to
verify(mNotesView).setProgressIndicator(true);
and the test passed.
why?
In my installation of Android Studio (2.2.3), there is no Code Coverage selection/configuration. It would be nice if the codelab could be extended to instruct the user on how to correct such a situation if it exists.
This link will provide the user with basic help on how to configure Code Coverage.
https://www.jetbrains.com/help/idea/2016.3/code-coverage.html
There are still a few small spelling and grammar mistakes, but we will overlook them.
This is a very good code lab to help the student get started with writing their own tests.
Kind regards,
MPongrac
I hit run button for Tests in com.android...
build config.
See gradle tasks: Executing tasks: [:app:assembleProdDebug, :app:assembleProdDebugAndroidTest]
Finally the run console says:
11/02 19:00:04: Launching Tests in 'com.example.android.testing.notes'
$ adb push /Users/bag/codelab/android-testing/app/build/outputs/apk/app-prod-debug.apk /data/local/tmp/com.example.android.testing.notes
$ adb shell pm install -r "/data/local/tmp/com.example.android.testing.notes"
WARNING: linker: /system/lib/libhoudini.so has text relocations. This is wasting memory and prevents security hardening. Please fix.
pkg: /data/local/tmp/com.example.android.testing.notes
Success
The APK file /Users/bag/codelab/android-testing/app/build/outputs/apk/app-prod-debug-androidTest.apk does not exist on disk.
Error while Installing APK
It's looking for the app-prod-debug-androidTest.apk
while there is no zipaligned version of this apk, there are only:
bag@iMac-Dmitry:~/codelab/android-testing/app/build/outputs/apk (step-7) $ ls
app-prod-debug-androidTest-unaligned.apk
app-prod-debug-unaligned.apk
app-prod-debug.apk
If I manually rename the file to app-prod-debug-androidTest.apk
, the job completes:
11/02 18:57:31: Launching Tests in 'com.example.android.testing.notes'
$ adb push /Users/bag/codelab/android-testing/app/build/outputs/apk/app-prod-debug.apk /data/local/tmp/com.example.android.testing.notes
$ adb shell pm install -r "/data/local/tmp/com.example.android.testing.notes"
WARNING: linker: /system/lib/libhoudini.so has text relocations. This is wasting memory and prevents security hardening. Please fix.
pkg: /data/local/tmp/com.example.android.testing.notes
Success
No apk changes detected since last installation, skipping installation of /Users/bag/codelab/android-testing/app/build/outputs/apk/app-prod-debug-androidTest.apk
$ adb shell am force-stop com.example.android.testing.notes.test
Running tests
$ adb shell am instrument -w -r -e package com.example.android.testing.notes -e debug false com.example.android.testing.notes.test/android.support.test.runner.AndroidJUnitRunner
Client not ready yet..
Started running tests
What to do to run the tests?
When running the first espresso test from step 7 i got this error:
java.lang.IncompatibleClassChangeError: com.example.android.testing.notes.notes.NotesActivity
the only way i was able to fix it was to include in the gradle file:
androidTestCompile ("com.android.support.test.espresso:espresso-contrib:$rootProject.ext.espressoVersion") {
exclude group: 'com.android.support', module: 'appcompat'
exclude group: 'com.android.support', module: 'support-v4'
exclude module: 'recyclerview-v7'
}
Am i doing something wrong?
Btw, great codelab :)
I added this config block to my gradle
however I ran into the following issue:
https://stackoverflow.com/questions/47301670/espresso-tests-cannot-access-class-file
Once i removed it the errors went away and my espresso test ran successfully.
Hi. In step 7 the following sentence:
JUnit test rules allow the alteration of test methods. It is run before any test...
Contains a link in the words "JUnit test rules" which points to http://junit.org/apidocs/org/junit/rules/TestRule.html. This website gives a 404 now. The URL should be updated.
@slinzner Could we add TravisCI so users can see a working example of espresso?
In the following description, after the FAB is clicked, the text says that Espresso will wait for the new screen, by waiting on the View with id R.id.fab_add_notes
. This should instead reference a view on the new screen, i.e. R.id.add_note_title
. I've marked the incorrect id in the excerpt below:
Similar to the previous Espresso test we looked at, we will first find the floating action button (
R.id.fab_add_notes
) and click it:
// Click on the add note button
onView(withId(R.id.fab_add_notes)).perform(click());
Next (once the "add note screen" is open) we will enter our note text and save the note. (We don't need to wait for the new screen to open - Espresso will do this automatically for us. It waits until a View with the id >>>
R.id.fab_add_notes
<<< can be found.)
// Add note title and description
onView(withId(R.id.add_note_title)).perform(typeText(newNoteTitle), closeSoftKeyboard()); // Type new note title
onView(withId(R.id.add_note_description)).perform(typeText(newNoteDescription),
closeSoftKeyboard()); // Type new note description and close the keyboard
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.