2015年2月22日星期日

用Swift语言做App开发之单元测试 - Justin X

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
用Swift语言做App开发之单元测试 - Justin X  阅读原文»

作为一个有质量保障的应用程序,当然少不了单元测试;Swift开发的App也亦如此,此文将以一个简单的实例来介绍Swift中的单元测试。

这里我们使用XCode模版自带的XCTest框架,此框架包含了一个名为XCTestCase的类,所有的测试类都应该继承自它;按照约定俗成所有的测试方法名都应以test开头,并不能包含任何参数,只有这样,这些测试方法才能在运行测试时被自动执行;在每个测试方法里面,我们可以通过调用XCTAssert*函数去断言一个操作成功与否,如判等函数XCTAssertEqual、大于函数XCTAssertGreaterThan等;

话不多说,请先使用XCode创建一个iOS的Single View Application项目,并选择Swift作为开发语言。

大家可以看到创建完成后的目录结构应该是如此(这里我的项目名为TestDemo):

默认的模版会创建两个文件夹,一个和项目名同名(这里是TestDemo),用于放置App的主程序;另外一个则是“项目名+Tests”(这里是TestDemoTests),用于放置测试代码;

这里要注意的是,你要测试的类需要在Test中使用到,所以你在创建类文件时需要在Targets中同时选择TestDemo和TestDemoTests;

如我在主应用程序中添加一个名为Url的类:

创建完成后,录入代码:

1 class Url {
2 let baseUrl: String
3
4 init(baseUrl: String) {
5 self.baseUrl = baseUrl
6 }
7
8 func getActualPathFrom(resourcePath: String, segments: [String:String]) -> String {
9 var actualPath = resourcePath
10 for (key,value) in segments {
11 var segmentPlaceHolder = "{\(key)}"
12 actualPath = actualPath.stringByReplacingOccurrencesOfString(segmentPlaceHolder, withString: value, options: .LiteralSearch, range: nil)
13 }
14 return baseUrl + actualPath
15 }
16 }

然后在TestDemoTests文件夹下创建UrlTests文件,此时由于该类只需要在测试中才能用到,所以只需要在Targets选择TestDemoTests就可以了:

创建完成后,导入XCTest框架,并使该类继承自XCTestCase,然后录入测试代码:

import XCTest

class UrlTests: XCTestCase {
var urlInstance = Url(baseUrl: "http://localhost:8080/api/")

func testShouldGetCorrectPathWhenNoSegmentProvided() {
let resourcePath
= "customers"

let result
= urlInstance.getActualPathFrom(resourcePath, segments: [String:String]())

XCTAssertEqual(result,
"http://localhost:8080/api/customers", "Can not get corrent path when no segments provided")
}

func testGetCorrectPathGivenOneSegment() {
let resourcePath
= "customer/{id}"

let result
= urlInstance.getActualPathFrom(resourcePath, segments: ["id": "10"]);

XCTAssertEqual(result,
"http://localhost:8080/api/customer/10", "Can not get corrent path when only one segment provided")
}
}

最后Command+U执行测试


本文链接:用Swift语言做App开发之单元测试,转载请注明。

Java外观模式(Facade模式) - Coda  阅读原文»

外观模式(Facade)的定义:为子系统中的一组接口提供一个一致的界面。

Facade一个典型应用就是数据库JDBC的应用,如下例对数据库的操作:

public class DBCompare {
 Connection conn
= null;
 PreparedStatement prep
= null;
 ResultSet rset
= null;
 
try {
  Class.forName(
"<driver>" ).newInstance();
  conn
= DriverManager.getConnection( "<database>" );
    
  String sql
= "SELECT * FROM <table> WHERE <column name> = ?";
  prep
= conn.prepareStatement( sql );
  prep.setString(
1, "<column value>" );
  rset
= prep.executeQuery();
  
if( rset.next() ) {
    System.out.println( rset.getString(
"<column name" ) );
  }
 }
catch( SException e ) {
  e.printStackTrace();
 }
finally {
  rset.close();
  prep.close();
  conn.close();
 }
}

上例是Jsp中最通常的对数据库操作办法。

在应用中,经常需要对数据库操作,每次都写上述一段代码肯定比较麻烦,需要将其中不变的部分提炼出来,做成一个接口,这就引入了facade外观对象。如果以后我们更换Class.forName中的<driver>也非常方便,比如从Mysql数据库换到Oracle数据库,只要更换facade接口中的driver就可以。

我们做成了一个Facade接口,使用该接口,上例中的程序就可以更改如下:

public class DBCompare {
 String sql
= "SELECT * FROM <table> WHERE <column name> = ?";  
 
try {
  Mysql msql
=new mysql(sql);
  prep.setString(
1, "<column value>" );
  rset
= prep.executeQuery();
  
if( rset.next() ) {
   System.out.println( rset.getString(
"<column name" ) );
  }
 }
catch( SException e ) {
  e.printStackTrace();
 }
finally {
  mysql.close();
  mysql
=null;
 }
}

可见非常简单,所有程序对数据库访问都是使用改接口,降低系统的复杂性,增加了灵活性。

如果我们要使用连接池,也只要针对facade接口修改就可以。

Java 外观模式

由上图可以看出,facade实际上是个理顺系统间关系,降低系统间耦合度的一个常用的办法,也许你已经不知不觉在使用,尽管不知道它就是facade。


本文链接:Java外观模式(Facade模式),转载请注明。

阅读更多内容

没有评论:

发表评论