阅读更多
技巧一:处理实例化

在我想办法让我的Android App通过Unit Test和Integration Test的过程中,我积累了一些小的经验与技巧,可以成功的处理比较麻烦的代码。展示开始:

问题代码


我想测试这段代码
public void readDeepLink(String path) {
    new DeepLinkReader().readDeepLink(path);
}

我只是想确保readDeepLink()方法执行了,但是我不想真的实例化DeepLinkReader因为这会引起网络操作。所以怎么修改呢?

解决方法

将实例化DeepLinkReader的代码封装到另外一个方法中,这样就可以用一个mock覆盖这个方法,这就可以避免在测试时实例化DeepLinkReader而可以使用Mockito来确认mock方法的执行。

解决代码
//在MainPresenter.java中
public void readDeepLink(String path) {
    getDeepLinkReader().readDeepLink(path);
}

DeepLinkReader getDeepLinkReader() {
    return new DeepLinkReader(currentData, events);
}

//在MainPresenterTest.java中
@Mock private DeepLinkReader deepLinkReader;

@Test  
public void shouldReadDeepLink() throws Exception {  
    MainPresenter mainPresenter = new MainPresenter() {  

        DeepLinkReader getDeepLinkReader() {  
            return deepLinkReader;  
        }  
    };  

    mainPresenter.readDeepLink("washingtonpost.com");  

    verify(deepLinkReader).readDeepLink("washingtonpost.com");  
}

技巧二:第三方类库

当你在为Anddroid App编写单元测试时,可能经常要处理第三方类库的API。在下面的代码中我用Picasso加载图片。Picasso的类库非常简洁,所以很好操作,但当你用其他的第三方类库时可能就不是这样了。所以我们怎么简化和第三方类库的交互而同时编写可维护性强的代码呢?
Picasso.with(contextLocal)
    .load(book.getImageUrl())
    .resize(80,108)
    .centerInside()
    .into(viewHolder.imageView)

我们可以将对第三方类库(这里以 Picasso 为例)的调用封装到另一个类中,使我们可以使用API并通过Assertion进行测试。

原始代码
//MyClass.class
public void loadImageFromUrl(String imageUrl) {
    presenter.setCurrentPreviewImageUrl(imageUrl);
    if (showThumbImage) {
        Picasso.with(context)
            .load(imageUrl)
            .into(thumbImageView);
    }
}

在这个 loadImageFromUrl 方法中,我们希望确保我们的 Presenter 被调用了,而且当 showThumbImage 是 true 的时候加载图片。因为我们想在单元测试中验证这一点,所以我们不想真正加载这张图片。

为了达到目标我们新建两个类:ImageLoader 和 ImageLoaderImpl,第一个是用于暴露API的接口,第二个是实现了第一个接口的类,用于封装调用第三方API的操作。

修改代码
// ImageLoader interface
public interface ImageLoader {  
    void loadImage(String imageUrl, ImageView imageView);  
}

// ImageLoaderImpl class
public class ImageLoaderImpl implements ImageLoader {
    // fields omitted  
    @Override  
    public void loadImage(String imageUrl, ImageView imageView) {  
        Picasso.with(context).load(imageUrl).into(imageView);  
    }  
}

//loadImageFromUrl method
public void loadImageFromUrl(String imageUrl) {
    presenter.setCurrentPreviewImageUrl(imageUrl);
    if (showThumbImage) {
        imageLoader.loadImage(imageUrl, thumbImageView);
    }
}

Unit Test
//MyClass
@Mock private ImageLoader imageLoader;  

@Test  
public void shouldLoadImageWhenShowThumbIsTrue() throws Exception {  
    myClass.setShowThumbImage(true);
    myClass.loadImageFromUrl("http://www.myimageurl.png");
    verify(imageLoader).loadImage(anyString(), any(ImageView.class));
}

@Test  
public void shouldNotLoadImageWhenShowThumbIsFalse() throws Exception {  
    myClass.setShowThumbImage(false);
    myClass.loadImageFromUrl("http://www.myimageurl.png");
    verifyZeroInteractions(imageLoader);
} 

在这两个单元测试中我们可以成功地测试了 Image Loader 的相关操作而无需关心第三方API。而且如果将来要使用其他的图片加载类库,也无需改变测试代码。

技巧三:提高可读性

可读性是高质量测试代码的重要指标之一,而我们有可能会因为在测试中添加了无用的信息而降低可读性,来看个实例。

例子

我们现在要测试我们用于创建 Video Object 的URL与调用 VideoPlaybackService 中的 playCurrentVideo 方法的返回值适配。我们编写了一个helper方法,可以传入用于实例化 Video Object 的一些参数。但是大多数情况下我们不需要设置所有的参数,比如 duration 和 displayDate 对于这个方法的测试就不起到任何作用。也就是说,我们在测试中添加了额外的且无用的信息,使测试代码可读性降低。
@Test
public void shouldReceiveCurrentUrlWhenVideoAvailable() {
    String url = "http://www.my_video.mp4";
    String displayDate = "Jan. 08, 2016";
    double duration = 0.30;

    playbackService.setCurrentVideo(createVideo(url, displayDate, duration));

    String actualUrl = playbackService.playCurrentVideo();

    assertEquals("the urls are not the same", url, actualUrl);
}

private Video createVideo(String url, String displayDate, double duration) {
    Video video = new Video();
    video.setUrl(url);
    video.setDisplayDate(displayDate);
    video.setDuration(duration);

    return video;
}

解决方案

我们可以通过使用建造者(Builder)模式优化 Video 类,从而使额外的属性不再是必需的。下面是视频的URL的setter方法的未经优化的代码。
public void setUrl(String url) {
    this.url = url;
}

我们可以升级这个方法,使它回传Video对象(this)而不是返回空。让我们看一看这可以怎样增强测试代码的可读性和理解性。

使用建造者模式
public Video setUrl(String url) {
    this.url = url;
    return this;
}

@Test
public void shouldReceiveCurrentUrlWhenVideoAvailable() {
    String url = "http://www.my_video.mp4";
    playbackService.setCurrentVideo(new Video().setUrl(url));

    String actualUrl = playbackService.playCurrentVideo();

    assertEquals("the urls are not the same", url, actualUrl);
}

这样代码就具有更强的可读性和可维护性了。

本文转自:http://blog.chengdazhi.com/
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 【easyui】之DataGrid数据显示

    easyui继续走起!

  • EasyUI——DataGrid数据显示

    DataGrid数据显示

  • EasyUI之datagrid展示数据列表

    写在最前: 如果你用惯了Web Mvc框架的视图跳转方式来开发后台系统,第一次接触到EasyUI的时候,往往会有一个大大的疑问,这EasyUI是如何做跳转的啊?增删改查都不知道如何下手了!但是当你知道有RestFul编程的时候。你会恍然大悟:我靠,RestFul+EasyUI简直就是绝配呀!博主就是如此:在写完一个增删改查之后,才发现EasyUI越学越有意思,页面都是靠局部刷新来动态展示数据,这...

  • DataGrid显示后台数据

    由于这两三周都非常的忙,不仅是公司还是考研,弄得我没有了之前的节奏感。现在研考完了,公司也不忙了,写篇博客吧 。。    这篇博客很简单,主要写的是 DataGrid显示后台数据,通过这篇博客会了解到datagrid的用法、json的用法、以及json特殊字符过滤。    一、JS中的DataGrid    ta为table标签    二、json获取数据    三、js

  • DataGrid简单的显示数据

    Flex中基于List的组件是RIA的重要组成部分,List不仅能够胜任显示数据的大批任务,而且还能为用户提供许多便利,如:列排序和自动换行,从而增强Flex应用程序的可用性。 上图为基于列表的一系列MX组件及相互的关系。 由于flex已经很少在使用,逐渐的被JS所替代,网上相应的API很多也停止了更新,这里为ActionScript3.0的查询参考文档。https://help.adob...

  • SpringData JPA easyUI dataGrid数据显示的解决经验

    最近,初学SpringMVC,用的是springDataJPA。前台用的是EasyUI的datagrid显示数据。刚开始,搞了半天数据就是表示不出来,后台代码运行正常,前台js也没问题。蛋疼的一个下午,晚上看了部电影回来就解决了。下面是我的代码,及解决的方法,以此仅是记录个人经验,希望大家多多指教。 JPA的代码就不在此记录,个人感觉很简单,可参照官网http://docs.spring.io/

  • WPF DataGrid 展示数据

    DataGrid 经常用作数据的展示,例如: 2. 后台代码 创建一个DataTable 数据源,在窗口初始化时绑定。DataTable的原始数据可以来自数据库,文件等。

  • ComBox和DataGrid

    ComBox和DataGrid显示 ArrayCollection数据的基本操作效果图: 代码:  http://ns.adobe.com/mxml/2009"       xmlns:s="library://ns.adobe.com/flex/spark"       xmlns:mx="library://ns.adobe.com/flex/mx" minWidth=

  • C# 动态修改DataGridView数据源,根据不同条件显示不同数据

    在实际应用中,需要动态根据程序执行中的数据显示不同数据表中的数据,两个表中的数据列有一些并不相同,因此不能使用相同的数据列显示。 可以在每次绑定之前先清空所有数据列,然后根据数据源的信息让程序自动再生成数据列 string sql = @"SELECT * FROM QQ "; DataView.Columns.Clear(); ...

  • WPF 之 DataGrid 入门实践二:数据保存

    ▪ 前言 在 《WPF 之 DataGrid 入门实践一》 中,我们已经初识 DataGrid 控件,也看到了 DataGrid 的样子。接下我们就要学习 DataGrid 最为重要的功能,就是保存修改后的 DataGrid 数据。 ▪ 基础代码 在 《WPF 之 DataGrid 入门实践一》 中,我们已经构建显示在 DataGrid 表中的数据,为了适应本章的内容,我们稍微重构了 实践一 中的基础代码。 重构前台 XAML 代码: # xaml <DataGrid x:Name="uiStuden

Global site tag (gtag.js) - Google Analytics