Happy Coding, Happy Life

Dora诞生记

| Comments

趁着在墨尔本和西安Office上Hackday获奖的喜悦劲,赶紧来一篇Dora诞生记。
提醒偶记住这个特殊的日子,同时也感谢在过去两个月,牺牲个人时间,奋斗在Dora(X-Robot)上的Casa的兄弟姐妹们。

-2013年10月20

和Charley午餐的时候,无意间谈论起了各自想做但没时间做的idea。

幸运乎,找到一个我俩都认为不错但又没被完全实现的一个想法<<公交来了>>(旨在帮助等车族们准确的掌握公交将来的时间,为既不想迟到又想多赖几分钟在床上的兄弟提供福音)。

WebRTC - Understand the PeerConnection

| Comments

在上篇文章里,我们已经了解了MediaStream。那么这篇文章里,我们就来重点了解RTCPeerConnection。

RTCPeerConnection表示浏览器之间点对点的连接。只有当连接建立后,浏览器的两端才能真正完成流媒体数据的传输。

还记得之前讨论过的WebRTC架构图吗? 实际上,虽然RTCPeerConnection是一个暴露的连接接口, 但其内部封装了大量WebRTC编解码和协议处理的工作,因此使浏览器之间点到点的即时通讯变得简单。

WebRTC - Understand the MediaStream

| Comments

WebRTC从设计之初,目的就是为开发人员提供更加简便的方式构建基于Web的视频、音频应用。对于任何的WebRTC应用程序,只需要做如下几件事情:

  • 1)获取本地媒体流(音频、视频)。
  • 2)与对端建立连接(包括防火墙和NAT的穿透)。
  • 3)初始化双方通信信道。
  • 4)交换通信元数据信息,比如分辨率、编解码方案、网络地址等。
  • 5)开始音频,视频或数据的通信。

WebRTC - the Revolution of Media Communication

| Comments

什么是WebRTC

如今,互联网主流的音频、视频通信服务产品,如Skype, QQ, GTalk等, 都是各自厂商私有的技术。用户需要安装插件或者桌面客户端,才能使用其提供的音频或者视频通信功能。 如果某天,不使用任何插件,只通过浏览器,就能实现手机、平板、电视和电脑的视频或者音频通信;那会是什么场景? 而这正是WebRTC的愿景。

WebRTC(Web Real-Time Communication)由一套开放的标准、协议和一组JavaScript API构成。2010年,谷歌收购了VoIP软件开发商GIPS(Global IP Solutions),并获得了视频采集、编解码、网络传输、回音消除等RTC相关技术。2011年6月,谷歌开放了该部分源码,并积极推动该项技术,这奠定了RTC在Web领域发展的基础。

WebRTC使浏览器之间能够通过点对点的通信方式,直接完成视频、音频以及数据的实时传输。同时,WebRTC容许开发人员通过调用浏览器支持的API,使用HTML5标签和JavaScript轻松的实现基于Web的音频、视频应用。

目前,WebRTC的标准还在不断完善中,W3C、IETF和其他一些浏览器厂商正在积极的推动WebRTC的发展。WebRTC开创了浏览器之间能够直接通信并完成视频或者音频传输的新时代。对于构建开放的、标准的,无插件,免费的视频音频通信应用,迈出了划时代的一步。

Page Object Understanding

| Comments

什么是Page Object

Page Object是Selenium中提出的一种测试设计模式。在Web前端自动化测试的过程中,Page Object可以称得上是居家必备的良品之一。PageObject将与Web测试页面交互的行为封装在其内部,旨在将每个页面或者相似页面的功能封装,例如页面中需要测试的元素(按钮,输入框,标题等),这样,通过在测试中访问Page类的相应方法来获取页面相应的元素,从而巧妙的避免了当页面元素id或者位置变化时,需要修改测试代码的情况。

言而总之,总而言之,PageObject就是将Web页面元素的变化封装起来,提供API供外部测试代码调用,从而达到将测试代码于Web页面元素的变化解耦。

Arduino, Make Hardware Development Easy

| Comments

顺应Open Hardware的潮流,Team里最近买了块 Arduino的板子。于是乎,偶也就有个机会,能倒腾倒腾了。

介绍

Arduino 是一个开源、易于使用的硬件设备。其上的微控制器可以通过Arduino Style的编程语言来编写程序,编译成二进制文件,并烧录进微控制器。 Arduino 能通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。和传统的单片机有点类似,但是更易于使用,对于开发者也更加友好。

环境搭建

  • 当然,先买块Arduino的板子。国内的商家'奥松'还不错(非广告贴,只是个人经验),可以天猫之。:)

Mockito - Partial Mock

| Comments

Mockito是一个方便的java测试Mock工具。

当我们做TDD或者单元测试的时候,为了消除当前被测对象和其依赖之间的关系,经常使用Mockito。

本篇文章只涉及如何使用Mockito的Partial Mock。关于Mockito的其他用法,请参照Mockito

1. 什么是Partial Mock

在单元测试的过程中,偶尔会出现这种情况。对于一个对象,某些方法需要被mock,而某些方法希望被直接调用,这时候,我们就需要借助Partial Mock。

2. 使用Partial Mock的场景

在如下两种场景中,Partial Mock就显得相当犀利:

a) 测试存在具体方法的抽象类

1
2
3
4
5
6
7
8
public abstract class AbstractHandler {

    public String greet() {
        return "Hello " + fetchName() + "!";
    }
 
    protected abstract String fetchName();
}

如上代码所示,抽象类AbstractHandler中定义了方法greet(),并且该方法存在一定逻辑。 此时,如果希望测试greet(),可以选择两种方式:

  • 构建其派生非抽象类,如ConcertHandler,再进行测试。
  • 使用Partial Mock,它可以省去构建派生类的步骤,直接对该抽象类进行测试,代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
public class AbstractHandlerTest {
      
    @Test
    public void shouldCallRealMethodsAndFakeAbstractMethod() {
        AbstractHandler handler = mock(AbstractHandler.class);

        when(handler.greet()).thenCallRealMethod(); 
        when(handler.fetchName()).thenReturn("Geek");

        assertThat(handler.greet(), is("Hello Geek!"));
    }
}

如代码所示,对于抽象方法fechName(),直接mock其返回值 when(handler.fetchName()).thenReturn(“Geek”);

对于被测方法greet(),则使用thenCallRealMethod()使Mock对象调用真实的实现方法。 when(handler.greet()).thenCallRealMethod();

b)测试过分依赖于I/O操作的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public class BooksController {

    protected Map<String, Date> fetchBooks(){
        //fetch the books from different publishing company.
        service1.retrieveBooks();
        service2.retrieveBooks();
        ......
        service10.retrieveBooks();

    }

    protected List<String> getPublishedBooks(){

        books = fetchBooks();
        //only pick up the books published.
    }
}

如上代码所示,类BooksController中定义了方法fetchBooks(),并且该方法严重依赖于I/O操作。因为fetchBooks()从不同的供应商那里获取最近的书籍信息。

对于这种测试,也有两种方案:

  • Mock所有的service返回结果,然后测试getPublishedBooks()。
1
2
3
doReturn(xxxx).when(service1).retrieveBooks()
doReturn(xxxx).when(service2).retrieveBooks()
doReturn(xxxx).when(service3).retrieveBooks()
  • 除此之外,也可以考虑在测试getPublishedBooks()的时候,对fetchBooks()方法进行mock。如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BooksControllerTest {

    @Test
    public void shouldReturnPublishedBooks(){
        BooksController controller = spy(new BooksController());

        Map<String, Date> books = new HashMap<String, Date>();
        books.put("XXX1", "2014-2-1");
        books.put("XXX2", "2014-3-1");

        doReturn(books).when(controller).fetchBooks();

        assertThat(controller.getPublishedBooks(), is(....));
    }

}

在如上的代码中,controller是BookController一个真实的实例,非mock对象。 原因是当前被测类为BooksController,因此不能将该类的实例定义成mock。
另外,controller的fetchBooks()方法虽然被partial mock了,但其他的方法还是该实例真正的方法。

因此,Spy的作用是将原本被实例化的对象,附上了Mock的功能。

注意,该场景完全是为了演示Partial mock。在实际情况中,如将books作为实例变量,并提供setBooks(List books)方法,根本不需要mock就能完成对getPublishedBooks的测试。另外,对于这种使用Spy的Partial Mock场景,大多数情况也是因为类的设计违背了SRP原则。

3. 两种Partial Mock方式

让我们再回顾一下上面的例子,并总结一下Partial Mock的两种用法:

  • 使用Mock构建对象,再使用CallRealMethod指定某方法为真实调用。

  • 实例化对象,定义Spy,再使用doReturn(xxx).when(xxx).method()

4. 区别

起初,偶比较倾向于使用CallRealMethod。因为该方法名足够表意,很容易就能理解其带来的用途。 不过,使用CallRealMethod却不是推荐的方式,为什么呢,请看如下代码:

@Test
public void testListPartialMockByCallRealMethod(){
    List<Integer> list = mock(ArrayList.class);
    when(list.add(100)).thenCallRealMethod();

    list.add(100);
    verify(list).add(100);
}

代码没问题吧,不过运行后,却得到如下错误:

java.lang.NullPointerException
    at java.util.ArrayList.add(ArrayList.java:352)
    at com.wl.tw.VersionInfoCheckTest.testListByCallRealMethod(VersionInfoCheckTest.java:59)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

如果查看ArrayList.java:352的代码,就会发现

350    public boolean add(E e) {
351        ensureCapacity(size + 1);  // Increments modCount!!
352        elementData[size++] = e;
353        return true;
354    }

在第352行,ArrayList实际上使用了另外一个对象elementData来存放新加入的元素。

在这个例子中,由于ArrayList是mock的,并不是实例化出来的,所以mock的ArrayList并没有初始化elementData对象。这就是为什么会出现NullPointerException的原因。

5. 总结

  • 当使用mockito mock对象时,它并不会mock该对象内部的其他依赖对象。
  • 当使用mockito partial mock时,注意spy和CallRealMethod的区别。

Vagrant Learning - 4 (Provision)

| Comments

如何安装应用

当我们第一次使用Box创建VM时,它通常是个没有装太多应用的裸机。所以,就会面临一个问题: 如何快速并有效的安装工作需要的软件,如数据库、Web服务器等?

目前,基本上有两种方式:

手动安装

Vagrant Learning - 3 (Box)

| Comments

什么是Vagrant Box

谈论完了Vagrantfile,让我们看看Vagrant的另外一个重要概念Box。它是Vagrant运行VM的必要条件。 基本上,从头开始建立一个VM是相当耗时的工作,于是Vagrant使用一个基础映像(base image), 克隆它并快速创建一个可用的VM。
在Vagrant的世界里,所有这些基础映像统称为Box。简单地说,Box可以理解为创建VM时需要的模板,通过这些模板,我们可以创建VM。

Vagrant Learning - 2 (Configuration)

| Comments

Vagrantfile

Vagrantfile是Vagrant启动并设置VM的配置文件,每个VM都必须有一个Vagrantfile。 当执行Vagrant init,Vagrant便会帮我们生成一个默认的Vagrantfile。 当然,不同的VM可以根据需求更改Vagrantfile的配置信息。

对于开发团队,我们可以将Vagrant配置文件放入版本管理系统,从而整个团队能够共享并不断改进该文件,在团队内部提供一种方便快捷的方式,构建产品运行环境。

譬如,我们可以执行如下代码生成Vagrantfile

mkdir vm && cd vm  
vagrant init precise64 http://files.vagrantup.com/precise64.box

Vagrant会提示

A Vagrantfile has been placed in this directory. You are now
ready to 'vagrant up' your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
'vagrantup.com' for more information on using Vagrant.

查看当前目录,会发现Vagrantfile已经生成。