# 初创团队的Android应用质量保障之道-稳定性与内存优化 应用示例部分
>
该项目为 [初创团队的Android应用质量保障之道](http://blog.csdn.net/bboyfeiyu/article/details/73716633) 的应用示例部分(应用架构、单元测试、Monkey、LeakCanary定制),由于时间有限,只能够写些简单的代码来讲述一个大致的过程。其中的代码有很多不合理之处,各位客官只需要了解其原理,然后将原理运用到自己的项目中即可。具体的代码结构、测试框架都可以自行替换.
核心要点:
1. 单元测试覆盖,提高开发、测试效率,保证底层基础类型的正确性. 测试对象: 非UI的Class都可以进行单元测试.
2. Monkey 压力测试 配合 LeakCanary, 获取崩溃信息、内存泄露信息
3. 通过Jenkins平台自动执行测试任务, 将结果通过邮件发送给开发人员. (夜间执行测试,第二天早上得到邮件反馈)
## jenkins 流程
对于Android项目来说,你可以理解为它可以定期的拉取代码,然后打包你的应用,并且执行一些特定的任务,例如打包之后运行单元测试、压力测试、UI自动化测试、上传到fir.im 上等。Jenkins的执行流程大致如图 1-1 所示 :
![](http://img.blog.csdn.net/20170418131739385)
图 1-1
Jenkins测试任务的执行步骤:
1. 获取最新代码(通过将github作为代码仓库)
3. 运行测试任务
4. 将测试报告通过邮件的形式发给相关人员
## Monkey 测试
1. 通过 gradle 执行 `./gradlew assembleMonkeyDebug` 命令生成 monkey flavor的apk包
2. 通过 shell 脚本安装上述apk
3. 执行monkey 命令运行monkey测试, 例如 `adb shell monkey -p com.simple.apptestarch --ignore-crashes --ignore-timeouts --ignore-native-crashes --pct-touch 40 --pct-motion 25 --pct-appswitch 10 --pct-rotation 5 -s 12358 -v -v -v --throttle 500 1000 2>~/monkey_error.txt 1>~/monkey_log.txt`, `com.simple.apptestarch` 为你的应用包名, 参数 1000代表事件的数量,测试时可以根据具体情况来设置,通常我们设置为 100000次 到 200000次。
4. 如果在测试过程中出现崩溃和内存泄露,相关信息会写入到sdcard对应的目录中
5. 测试完成,将相关日志通过邮件反馈给开发人员
崩溃日志的保存路径可以通过logcat来查看(可以自行修改):
```
log file name : /storage/emulated/0/com.simple.apptestarch/crash/2017-06-26-crash.txt
```
### Crash日志 `2017-06-26-crash.txt` 详细信息 :
```
java.lang.IllegalStateException: Detail Leak !!! Please check !
at com.simple.apptestarch.ui.detail.DetailActivity$1$override.run(DetailActivity.java:34)
at com.simple.apptestarch.ui.detail.DetailActivity$1$override.access$dispatch(DetailActivity.java)
at com.simple.apptestarch.ui.detail.DetailActivity$1.run(DetailActivity.java:0)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
```
崩溃日志很直观,直接暴露出来了崩溃的原因. 即 `com.simple.apptestarch.ui.detail.DetailActivity` 34行出的 `run`函数中抛出了一个 `java.lang.IllegalStateException `异常. 看到这个log之后到相应的类中处理掉即可.
### 内存泄露日志的保存路径可以通过logcat来查看(可以自行修改):
```
### *** onHeapAnalyzed in onHeapAnalyzed , dump dir : /data/user/0/com.simple.apptestarch/files/leakcanary
### log file name : /storage/emulated/0/com.simple.apptestarch/leak/2017-06-26-leak.txt
```
内存泄露的详细信息:
```
In com.simple.apptestarch:1.0:1.
* com.simple.apptestarch.ui.detail.DetailActivity has leaked:
* GC ROOT static com.simple.apptestarch.ui.detail.DetailActivity.sRecords
* references java.util.LinkedList.first
* references java.util.LinkedList$Node.item
* leaks com.simple.apptestarch.ui.detail.DetailActivity instance
* Retaining: 48 KB.
* Reference Key: dce6c099-4abe-4be1-abd8-0bdb24eb6082
* Device: motorola google Nexus 6 shamu
* Android Version: 7.1.1 API: 25 LeakCanary: 1.5 00f37f5
* Durations: watch=5009ms, gc=139ms, heap dump=1817ms, analysis=85866ms
```
log指出 `com.simple.apptestarch.ui.detail.DetailActivity `发生了内存泄露, 只有它的GC ROOT是 `com.simple.apptestarch.ui.detail.DetailActivity.sRecords`, 我们根据信息到DetailActivity类中,发现问题代码如下:
```
public class DetailActivity extends AppCompatActivity {
private static List<Activity> sRecords = new LinkedList<>() ;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// 这里有问题 !!!!
sRecords.add(this) ;
// 其他代码
}
}
```
此时只需要将DetailActivity对象在合适的时候从sRecords中移除即可. Jenkins执行Monkey测试、LeakCanary收集信息、邮件发送测试报告,整个过程都是通过自动执行,不需要我们人工干预,在快速开发时使得我们能够更快、更省心的发现问题。
## 单元测试
### Android 单元测试
测试代码目录为: `app/src/androidTest/java/`
![](http://img.blog.csdn.net/20170418131731443)
图 2-1 中将自动测试分为了三个层次,从下到上依次为单元测试、业务逻辑测试、UI测试,越往上测试成本越高、测试的效率越低,也就是说单元测试是整个测试金字塔中投入最少、收益最高、测试效率最高的测试类型。
* com.simple.apptestarch.services 包下为 Presenter的测试用例, 相当于业务逻辑测试;
* com.simple.apptestarch.services.unittest包下为单元测试
以 MainPresenterTestCase 中的testFetchNewsFromDb测试用例为例, 该测试用例的测试对象为 MainPresenter的fetchNews函数,代码如下:
```
public class MainPresenter extends Presenter<MainView> {
// 本地新闻源, 从数据库获取新闻
NewsDataSource mLocalSource ;
// 网络数据源, 从服务器获取新闻
NewsDataSource mRemoteSource ;
// 是否应该自动刷新
RefreshMonitor mRefreshMonitor;
public MainPresenter(NewsDataSource local, NewsDataSource remote, RefreshMonitor refreshMonitor) {
this.mLocalSource = local;
this.mRemoteSource = remote;
this.mRefreshMonitor = refreshMonitor;
}
private boolean isNotEmpty(List<News> newsList) {
return newsList != null && newsList.size() > 0 ;
}
public void fetchNews() {
// 1. 从数据库中读取缓存新闻
mLocalSource.fetchNews(new NewsListener() {
@Override
public void onComplete(List<News> newsList) {
// 2. 从数据库中如果到获取新闻则回调给 MainView
if ( getView() != null && isNotEmpty(newsList) ) {
getView().onFetchNews(newsList);
}
// 3. 如果缓存中没有新闻 或者 mRefreshMonitor.shouldRefresh() 返回true, 那么要从网络上获取新闻
if ( !isNotEmpty(newsList) || mRefreshMonitor.shouldRefresh()) {
mRemoteSource.fetchNews(mNewsListener);
}
}
});
}
NewsListener mNewsListener = new NewsListener() {
@Override
public void onComplete(List<News> newsList) {
if ( getView() != null ) {
getView().onFetchNews(newsList);
}
}
} ;
}
```
在 MainPresenter中我们将 mLocalSource、mRemoteSource、mRemoteSource作为外部依赖注入, 而不是在声明字段时直接使用new的形式创建, 例如`NewsDataSource
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
为了满足广大Android开发爱好者与从业者的学习需求,我们精心整理并上传了一份全面而实用的Android项目资源包。这份资源包内容丰富,涵盖了从基础知识到实战应用的全方位内容,旨在为开发者们提供一个便捷、高效的学习平台。 一、文件手册 资源包中的文件手册部分,详细记录了Android开发的核心知识点和常用技术。无论是初学者还是有一定经验的开发者,都能从中找到所需的学习资料。手册采用了简洁明了的排版方式,使得查阅更加方便快捷。同时,手册内容深入浅出,既适合新手入门,也能为老手提供有价值的参考。 二、项目实战与练习 为了让学习者能够将理论知识与实践相结合,我们特别准备了项目实战与练习部分。这部分内容包含了多个精心设计的Android项目案例,从需求分析、设计思路到实现过程,都有详细的讲解和代码示例。学习者可以通过实际操作,深入了解Android开发的整个流程,提升自己的实战能力。 此外,我们还提供了一系列练习题,旨在巩固所学知识,检验学习成果。这些练习题既有基础题,也有难度较高的挑战题,适合不同层次的学习者进行练习。 三、Android开发工具集 在Android开发过程中,选择合适的工具能够大大提高开发效率。因此,我们整理了常用的Android开发工具集,包括开发工具、测试工具、性能优化工具等。这些工具都是经过我们精心筛选和测试的,能够帮助开发者们更加高效地进行Android开发工作。 总的来说,这份Android项目资源包是一份不可多得的学习资料,无论你是初学者还是有一定经验的开发者,都能从中受益匪浅。我们希望通过这份资源包,为广大Android开发爱好者与从业者提供一个更加便捷、高效的学习平台,共同推动Android开发领域的发展。
资源推荐
资源详情
资源评论
收起资源包目录
Android 单元测试、Monkey、LeakCanary测试demo项目【粗略示例】.zip (61个子文件)
qinshihuangzailuguan
gradle.properties 730B
gradle
wrapper
gradle-wrapper.jar 52KB
gradle-wrapper.properties 233B
app
src
androidTest
java
com
simple
apptestarch
services
MainPresenterTestCase.java 5KB
unittest
NewsDAOTestCase.java 3KB
test
java
com
simple
apptestarch
PromotionCodeParserTest.java 2KB
main
java
com
simple
apptestarch
data
NewsDataSource.java 166B
NewsListener.java 225B
local
NewsDbSource.java 1KB
remote
NewsRemoteSource.java 1KB
utils
PromotionCodeParser.java 1KB
MainApp.java 1KB
ui
detail
DetailActivity.java 1KB
main
MainPresenter.java 2KB
RefreshMonitor.java 313B
MainActivity.java 4KB
MainView.java 272B
domain
News.java 216B
db
DatabaseHelper.java 2KB
contacts
NewsContact.java 695B
NewsDAO.java 2KB
res
mipmap-xxhdpi
ic_launcher.png 8KB
mipmap-hdpi
ic_launcher.png 3KB
mipmap-mdpi
ic_launcher.png 2KB
mipmap-xxxhdpi
ic_launcher.png 10KB
mipmap-xhdpi
ic_launcher.png 5KB
values-w820dp
dimens.xml 358B
values
dimens.xml 211B
colors.xml 208B
strings.xml 74B
styles.xml 363B
layout
news_item_layout.xml 923B
activity_main.xml 787B
activity_detail.xml 912B
AndroidManifest.xml 768B
proguard-rules.pro 683B
libs
simple_mvpbase.jar 5KB
build.gradle 1KB
.gitignore 7B
gradlew.bat 2KB
build.gradle 498B
.idea
sonarIssues.xml 8KB
runConfigurations.xml 564B
misc.xml 3KB
compiler.xml 686B
modules.xml 488B
gradle.xml 683B
encodings.xml 159B
copyright
profiles_settings.xml 74B
settings.gradle 31B
gradlew 5KB
.gitignore 118B
leakfortest
src
main
java
com
simple
leakfortest
LeakDumpService.java 967B
LeakCanaryForTest.java 2KB
StorageUtils.java 3KB
res
values
strings.xml 74B
AndroidManifest.xml 625B
proguard-rules.pro 683B
build.gradle 630B
.gitignore 7B
README.md 13KB
共 61 条
- 1
资源评论
01红C
- 粉丝: 1933
- 资源: 2139
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功