Saturday, August 13, 2011

Fedora 15 install Brisk and ruby on rails

First download Fedora 15 : )
Install it in vm or PC

Setup SSH : ) ( Ref.link )



Basic Setup SSH Server on Fedora.




Usually the ssh is install by default on the installation of Fedora operating system itself.  The article below show the step of the basic setup of ssh server on Fedora Linux operating system.

1.  Open X terminal.

X terminal.

Checking SSH server status.


Using the service command to check the current status of the sshd.

[root@tenouk ~]# service sshd status
sshd is stopped
[root@tenouk ~]#

Start SSH server.


Start the sshd process using service command.

[root@tenouk ~]# service sshd start
Starting sshd:                                             [  OK  ]
[root@tenouk ~]#

Automatically start SSH server.


   Using the chkconfig command to enable and make sure that every time the system restart, the SSH (sshd deamon) start automatically.

1.  Check current configuration status of sshd.

[root@tenouk ssh]# chkconfig --list sshd
sshd            0:off   1:off   2:off   3:off   4:off   5:off   6:off
[root@tenouk ssh]#

2.  Using the chkconfig to automatically start the SSH on runlevel 3, 4 and runlevel 5.

[root@tenouk ssh]# chkconfig --level 345 sshd on
[root@tenouk ssh]#

3.  Verify the change for shhd on runlevel 3, 4 and runlevel 5.

[root@tenouk ssh]# chkconfig --list sshd
sshd            0:off   1:off   2:off   3:on    4:on    5:on    6:off
[root@tenouk ssh]#


Install Java For Brisk:(Ref. link )

Using Sun Java Instead
If you require Sun Java or if OpenJDK does not work properly, you can download Sun Java and use it in Fedora.
Download the Java package from:
http://java.sun.com/javase/downloads/index.jsp. Always use the latest update.
Select: Java JRE 6 Update 18 (the JDK is for developers)
On the next page, for Platform select "Linux" for 32-bit users, and "Linux x64" for 64-bit users.
For Language select "Multi-language". Also accept the license agreement, and hit "Continue".
On the next page, select the RPM option:

Java SE Runtime Environment 6u17
jre-6u18-linux-i586-rpm.bin     (32-bit users)

jre-6u18-linux-x64-rpm.bin      (64-bit users) 

To install:

[mirandam@charon Download]$ sudo sh jre-6u18-linux-i586-rpm.bin
-OR-
[mirandam@charon Download]$ sudo sh jre-6u18-linux-x64-rpm.bin


Install Brisk

Install ruby
using yum, by default is 1.8.7 so we need rvm
yum install git 
yum install gcc 
Install rvm
bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

if you need to use head version ruby, you also need this.
rvm pkg install zlib


Install sqlite3  
yum install sqlite-devel


After that using bundle to update.

P.S. What the hell!!! gem update need a sudo??=_=凸

Monday, August 1, 2011

Raphaël—JavaScript Library for vector graphic

Raphaël—JavaScript Library

Essential TextMate Shortcuts, Tips and Techniques

Even after six years, TextMate is still considered by many to be the best code editor available for Mac. The reason why is simple: it’s incredibly powerful, and offers features that even the newest editors don’t yet offer. Add a robust plugin/bundle community on top of it, and you get one heck of a code editor.

I’ll show you some of my favorite shortcuts and tricks today.



1 – Vertically Select Text

Option + Drag

If you hold down the Option key, and drag the mouse, you’ll vertically select text. This can be particularly helpful when you need to update a block of text.

For example, let’s say we decide to remove the extra unnecessary var keywords from a bit of JavaScript? With vertical selection, this takes only a second.



2 – Alignment

Option + Command + ]

Many developers prefer to line up the symbols within arrays and objects. For example, rather than…

var kimberly = 'valley girl',

omg = 'oh my god!',

bieber = 'my home boy';

…many prefer:

var kimberly = 'valley girl',

omg = 'oh my god!',

bieber = 'my home boy';

This certainly makes for more readable code. If you’ve been lining up the equal signs manually, TextMate automates the process. Place the cursor on one of the related lines, press Option + Command + ], and TextMate will take care of the rest.


3 – Incremental Search

Control +

While the standard “popup” Command + f search functionality works, it’s decidedly slow. If you need to quickly search for a piece of text within the current page, use Control + s instead to perform incremental search.

A tiny textbox will pop up at the bottom of the screen. Once you’ve added your search query, press enter, and you’ll instantly be transported to the next occurrence of that sequence on the page. To continue searching, again, press Control + s and Control + Shift + s to continue forward and backward, respectively.



4 – Set Bookmarks

Command + F2

One of my favorite features in Vim is the ability to create “bookmarks” in your projects. This then allows you to immediately return to that line of code with a simple keystroke.

TextMate offers this functionality as well. To star, or bookmark a line of code, place the cursor on that line, and type Command + F2.


To return to this line of code (for instance, after scrolling up the page to find a particular variable name), type F2. If you have multiple starred lines, each time you press F2, you’ll be taken to the next applicable location.


5 – Save Time with Macros

Option + Command + m

Let’s imagine that there’s a sequence of actions you find yourself performing often. For example, what if you find – like I have – that you frequently change the entire contents of an HTML tag. Vim offers the ever convenient, cit command (change inner tag).

If you have the Zen Coding bundle installed, you can type Command + D to achieve the same effect. However, if you find that you often forget this shortcut, you can always record macros that will repeat any sequence of events as many times as your require.

To begin a macro, type Option + Command + M; you’ll see a red recording circle in the lower right portion of the editor. At this point, TextMate is now listening to every action you perform. In our simple example, we only need to type Command + D (balance tag), and then Delete to remove the text.

To conclude your recording, type the same sequence again: Option + Command + M. You may now repeat this sequence whenever you wish by typing Shift + Command + M.

Note that, when you create a macro in this way, it’s meant to be a temporary solution. Once you create a new macro, or restart the editor, you will lose you recording. For a more permanent solution, you should following #6 in this list!


6 – Create Permanent Macros

Control + Command + m

More often than not, you’ll need to access a variety of macros each day. You can record permanent macros in the same way that you did in #5 of this list. Once finished recording, type Control + Command + M to save the macro.

Once you do, a dialog box will pop up, where you can then assign a custom activation key sequence for future retrieval.


I often find myself typing:

echo '

';

print_r($variable);

echo '

';

Let’s create a custom macro to do the work for us. We begin by creating a macro, as outlined in #5. This macro will assume that our variable is stored within the clipboard. Type the snippet of code above manually as you normally would. When you get to print_r(), press Command + v to paste in the contents of the clipboard. Once finished, press Option + Command + m to conclude the macro.

Next, press Control + Command + m to save your macro; assign a tab trigger of debug, and you’re finished!


From now on, to print_r an array or object, simply copy the variable name to your clipboard, and type debug + TAB.


7 – Clipboard History

Control + Shift + Command + v

Many aren’t aware that TextMate has built-in clipboard history.

“By pressing ⌃⌥⌘V, you will see the list of all previous clippings and can pick the one you want to paste using arrow keys. Use return to insert it and escape to dismiss the list. If you dismiss the list, the currently selected clipping will be what gets pasted the next time you use the paste function.”


This is an incredibly useful feature that you’ll find yourself using constantly!


8 – Execute Shell Scripts

In addition to simple snippets, TextMate can also execute shell scripts. This means that all of the various web services are available for usage!

We’ll use my upcoming Prefixr service as an example. It allows you to automatically update a stylesheet to include the various prefix’ized versions of the new CSS3 properties. That way, you can code your stylesheets using the official W3C-recommended versions of each property, and Prefixr will fix in the missing pieces.

To hook into Prefixr’s HTTP-based API, create a new command in TextMate.

Control + Shift + Command + B

Next, add a new Command, and paste in the following shell script.

curl -sSG "http://www.prefixr.com/api/index.php" --data-urlencode "css=$TM_SELECTED_TEXT"


This instructs TextMate to run a shell script that performs a curl request to Prefixr.com. In the querystring, it passes the contents of what the TextMate user has selected with his mouse. That content is automatically represented, via the $TM_SELECTED_TEXT environment variable.

Note that we’re using the --data-urlencode parameter to ensure that the text you select is properly escaped and url encoded.

Lastly, assign a keyboard shortcut to execute this command, and you’re done! To use it, select your entire stylesheet (or a single CSS3 property), and type the shortcut that you specified. Your code will immediately be updated accordingly.

/* Before... */

#content {

border-radius: 5px;

box-shadow: 30px;

}

/* After... */

#content {

-webkit-border-radius: 5px;

-moz-border-radius: 5px;

-o-border-radius: 5px;

-ms-border-radius: 5px;

-khtml-border-radius: 5px;

border-radius: 5px;


-webkit-box-shadow: 30px;

-moz-box-shadow: 30px;

box-shadow: 30px;

}

Pretty nifty, ay?


9 – Auto-complete

Escape

Most IDEs offer the ability to autocomplete code – like method calls and variable references – typically by typing Control + Space. TextMate offers a similar feature, but via the Escape key instead. The key choice is a bit odd, but, of course, you can always map this to a different shortcut if you prefer. Simply type part of a variable or method name, press Escape, and TextMate will attempt to complete the word for you.

If you’d prefer project-wide autocompletion, you can also use Command + ;.


10 – Turbo-Charge the Editor

Ciarán Walsh, a few years ago, created Project Plus, which enhances TextMate in a number of ways – the most noticeable being that it replaces the often criticized elastic sidebar with a more traditional one.


It also offers excellent, status badges to keep track of – for Git purposes – which files have changed since last being committed.




11 – Switch the Page Language

Shift + Control + Option + {First-letter-of-language-choice}

Dependent upon which language you specify for a page (set automatically by default), you’ll have access to different syntax highlighting and commands.

Chances are, you’ll find yourself updating this often. It can be done manually by clicking the L button at the bottom of the editor.


This is a drag though. You can speed things up by typing Shift + Control + Option + {First-letter-of-language-choice}. For instance, if I want to change the page language to CSS, I’d type Shift + Control + Option + C.


12 – Download Custom Bundles

You’re certainly not limited to the dozen or so bundles that come preinstalled with TextMate. There’s a hugely robust community; you can download bundles and extensions for just about any language imaginable. A quick search on GitHub will return hundreds of results.

Download Nettuts’ CSS3 TextMate bundle.



13 – Search for a Command

Control + Command + T

There’s no denying it: it’s really difficult to remember all of these various commands. Rather than falling back to using the mouse and menu selections, instead type Control + Command + T. This will bring up a popup box, where you can then search for your desired command or snippet.



14 – Full Screen Mode in Lion

Now that Lion is officially available to the public, you can upgrade TextMate to provide full screen support, using this plugin.


15 – Speedy File Opening

Command + T

If you’re the type who requires lightning fast file switching, TextMate provides a built-in utility for opening files. Press Command + T to activate it.


However, if you’d prefer something a bit more robust and fuzzy, I highly recommend looking into PeepOpen, which works in a variety of editors. In addition to TextMate, I also use it in Vim.

” Search on both paths and filenames, and easily open the file in your text editor with a single keypress. Useful metadata helps you quickly choose the file you’re looking for.”



16 – FTP Access

An advantage that Espresso and Coda have over TextMate is that they offer built-in FTP access. This makes the process of editing files on your server as easy as possible. While TextMate doesn’t have a native solution to this problem, most Mac developers also use Panic’s popular Transmit app.


We can use these two apps in tandem to edit files on our servers. Transmit offers the ability to mount a directory on your computer.



With your server directory mounted, you can now open the directory from within TextMate. Each time you save a file, it will automatically be updated on your server as well. An elegant solution to a common gripe!


That’s All for Now!

I’ve barely scratched the surface of TextMate’s power. What are your favorite shortcuts and tricks? Let me know in the comments, and I just might update this article with your tip!

More TextMate Articles from Nettuts+





http://feedproxy.google.com/~r/nettuts/~3/wnUKqxYNgCI/


Monday, July 4, 2011

Facebook 的系统架构


根据我现有的阅读和谈话,我所理解的今天Facebook的架构如下:
  • Web 前端是由 PHP 写的。Facebook 的 HipHop [1] 会把PHP转成 C++ 并用 g++编译,这样就可以为模板和Web逻贺业务层提供高的性能。
  • 业务逻辑以Service的形式存在,其使用Thrift [2]。这些Service根据需求的不同由PHP,C++或Java实现(也可以用到了其它的一些语言……)
  • 用Java写的Services没有用到任何一个企业级的应用服务器,但用到了Facebook自己的定制的应用服务器。看上去好像是重新发明轮子,但是这些Services只被暴露给Thrift使用(绝大所数是这样),Tomcat太重量级了,即使是Jetty也可能太过了点,其附加值对Facebook所需要的没有意义。
  • 持久化由MySQL, Memcached [3], Facebook 的 Cassandra [4], Hadoop 的 HBase [5] 完成。Memcached 使用了MySQL的内存Cache。Facebook 工程师承认他们的Cassandra 使用正在减少,因为他们更喜欢HBase,因为它的更简单的一致性模型,以到其MapReduce能力。
  • 离线处理使用Hadoop 和 Hive。
  • 日志,点击,feeds数据使用Scribe [6],把其聚合并存在 HDFS,其使用Scribe-HDFS [7],因而允许使用MapReduce进行扩展分析。
  • BigPipe [8] 是他们的定制技术,用来加速页面显示。
  • 用来搞定用户上传的十亿张照片的存储,其由Haystack处理,Facebook自己开发了一个Ad-Hoc存储方案,其主要做了一些低层优化和“仅追加”写技术 [11].
  • Facebook Messages 使用了自己的架构,其明显地构建在了一个动态集群的基础架构上。业务逻辑和持久化被封装在一个所谓的’Cell’。每个‘Cell’都处理一部分用户,新的‘Cell’可以因为访问热度被添加[12]。 持久化归档使用HBase [13]。
  • Facebook Messages 的搜索引擎由存储在HBase中的一个倒置索引的构建。 [14]
  • Facebook 搜索引擎实现细节据我所知目前是未知状态。
  • Typeahead 搜索使用了一个定制的存储和检索逻辑。 [15]
  • Chat 基于一个Epoll 服务器,这个服务器由Erlang 开发,由Thrift存取 [16]
关于那些供给给上述组件的资源,下面是一些信息和数量,但是有一些是未知的:
  • Facebook估计有超过60,000 台服务器[16]。他们最新的数据中心在俄勒冈州的Prineville,其基于完全自定设计的硬件[17] 那是最近才公开的 Open Compute 项目[18]。
  • 300 TB 的数据存在 Memcached 中处理 [19]
  • 他们的Hadoop 和 Hive 集群由3000 服务器组成,每台服务器有8个核,32GB的内存,12TB的硬盘,全部有2万4千个CPU的核,96TB内存和36PB的硬盘。 [20]
  • 每天有1000亿的点击量,500亿张照片, 3 万亿个对象被 Cache,每天130TB的日志(2010年7月的数据) [21]
参考引用
[1] HipHop for PHPhttp://developers.facebook.com/blog/post/358
[2] Thrifthttp://thrift.apache.org/
[3] Memcachedhttp://memcached.org/
[4] Cassandrahttp://cassandra.apache.org/
[5] HBasehttp://hbase.apache.org/
[6] Scribehttps://github.com/facebook/scribe
[7] Scribe-HDFShttp://hadoopblog.blogspot.com/2009/06/hdfs-scribe-integration.html
[8] BigPipehttp://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
[9] Varnish Cachehttp://www.varnish-cache.org/
[10] Facebook goes for Varnishhttp://www.varnish-software.com/customers/facebook
[11] Needle in a haystack: efficient storage of billions of photos: http://www.facebook.com/note.php?note_id=76191543919
[12] Scaling the Messages Application Back Endhttp://www.facebook.com/note.php?note_id=10150148835363920
[13] The Underlying Technology of Messageshttps://www.facebook.com/note.php?note_id=454991608919
[14] The Underlying Technology of Messages Tech Talkhttp://www.facebook.com/video/video.php?v=690851516105
[15] Facebook’s typeahead search architecturehttp://www.facebook.com/video/video.php?v=432864835468
[16] Facebook Chathttp://www.facebook.com/note.php?note_id=14218138919
[17] Who has the most Web Servers?http://www.datacenterknowledge.com/archives/2009/05/14/whos-got-the-most-web-servers/
[18] Building Efficient Data Centers with the Open Compute Projecthttp://www.facebook.com/note.php?note_id=10150144039563920
[19] Open Compute Projecthttp://opencompute.org/
[20] Facebook’s architecture presentation at Devoxx 2010http://www.devoxx.com
[21] Scaling Facebook to 500 millions users and beyondhttp://www.facebook.com/note.php?note_id=409881258919
(全文完)

Sunday, June 5, 2011

COLLECTION & MEMBER METHODS WITHIN A ROUTE

RubyHunt: What’s the use of the :collection and :member methods within a route? What’s the difference between the two?
melvinram: Collection adds routes to the entire collection
RubyHunt: So the collection is used to add another action inside the controller
melvinram: If you had a resource of Contacts, a collection route you might add would be delete_all_older_than_6_months
melvinram: and the route to get to it would be be/contacts/delete_all_older_than_6_months/
RubyHunt: Which otherwise would be restricted to only 7 actions ?
melvinram: yes
melvinramA member method applies only to one record. For example, you might add a member method called upgrade_to_vip that would update one record to have a status of VIP or something…
melvinram: And the route would be /contacts/1/upgrade_to_vip
RubyHunt: So the :collection is used to add action inside a RESTful controller and the :member would be used to apply action for individual object.
melvinram: you got it!

Saturday, June 4, 2011

Ruby and Rails Naming Conventions


I’ve been looking for a consolidated list of all Ruby and Rails naming conventions without too much luck so I’ve started my own. I find I always forget the naming convention especially as I move between projects that use different languages.
Please let me know of any others that I have missed. 
Naming Conventions
Ruby Naming Convention
Ruby uses the first character of the name to help it determine it’s intended use.
Local Variables
Lowercase letter followed by other characters, naming convention states that it is better to use underscores rather than camelBack for multiple word names, e.g. mileage, variable_xyz
Instance VariablesInstance variables are defined using the single "at" sign (@) followed by a name. It is suggested that a lowercase letter should be used after the @, e.g. @colour 
Instance MethodsMethod names should start with a lowercase letter, and may be followed by digits, underscores, and letters, e.g. paint, close_the_door
Class VariablesClass variable names start with a double "at" sign (@@) and may be followed by digits, underscores, and letters, e.g. @@colour
Constant Constant names start with an uppercase letter followed by other characters. Constant objects are by convention named using all uppercase letters and underscores between words, e.g. THIS_IS_A_CONSTANT
Class and Module Class and module names starts with an uppercase letter, by convention they are named using MixedCase, e.g. module Encryption, class MixedCase
Global VariablesStarts with a dollar ($) sign followed by other characters, e.g. $global
Rails Naming Convention
Rails use the same naming convention as Ruby with some additions:
Variable Variables are named where all letters are lowercase and words are separated by underscores, e.g. order_amount, total
Class and Module Classes and modules use MixedCase and have no underscores, each word starts with a uppercase letter, e.g. InvoiceItem
Database Table
Table names have all lowercase letters and underscores between words, also all table names need to be plural, e.g. invoice_items, orders
Model
The model is named using the class naming convention of unbroken MixedCase and is always the singular of the table name, e.g. table name might be orders, the model name would be Order. Rails will then look for the class definition in a file called order.rb in the /app/models directory. If the model class name has multiple capitalised words, the table name is assumed to have underscores between these words.
Controller
Controller class names are pluralized, such that OrdersController would be the controller class for the orders table.  Rails will then look for the class definition in a file called orders_controller.rb in the /app/controllers directory.
Files, Directories and other pluralizationFiles are named using lowercase and underscores. Assuming we have an Orders controller then the following other conventions will apply:
  • That there is a helper module named OrdersHelper in the orders_helper.rb found in the app/helpers directory
  • Rails will look for view template files for the controller in the app/views/orders directory
  • Output from this view will then be used in the layout defined in the orders.html.erb in the app/views/layouts directory
  • Test files including order_test.rb will be created in the /test/unit directory, a file will be created in the /test/fixtures directory called orders.yml and finally a file called orders_controller_test.rb will be created in the /test/functional directory
Primary KeyThe primary key of a table is assumed to be named id.
Foreign Key
The foreign key is named with the singular version of the target table name with _id appended to it, e.g. order_id in the items table where we have items linked to the orders table.
Many to Many Link TablesTables used to join two tables in a many to many relationship is named using the table names they link, with the table names in alphabetical order, for example items_orders.
Automated Record TimestampsYou can get ActiveRecord to automatically update the create and update times of records in a database table. To do this create two specially named columns created_at and updated_at to your table, i.e. t.datetime :created_at and t.datetime :updated_at. If you only want to store the date rather than a date and time, use :created_on and :updated_on.
Naming Convention Summary 
Model Naming Convention
Table: orders
Class: Order
File: /app/models/order.rb
Primary Key: id
Foreign Key: customer_id
Link Tables: items_orders
Controller Naming Convention
Class: OrdersController
File: /app/controllers/orders_controller.rb
Layout: /app/layouts/orders.html.erb
View Naming Convention
Helper: /app/helpers/orders_helper.rb
Helper Module: OrdersHelper
Views: /app/views/orders/… (list.html.erb for example)
Tests Naming Convention
Unit: /test/unit/order_test.rb
Functional: /test/functional/orders_controller_test.rb
Fixtures: /test/fixtures/orders.yml
  

Saturday, April 23, 2011

Sunday, March 20, 2011

10句编程箴言,每个程序员都应该知道

10句编程箴言,每个程序员都应该知道


导读:原文作者Kevin Pang在kevinwilliampang.com发表一篇《10 Programming Proverbs Every Developer Should Know》。译文由开源社区编译成《10句编程箴言,每个程序员都应该知道》。文章内容如下:

所谓谚语,就是用言简意赅、通俗易懂的方式传达人生箴言和普遍真理的话,它们能很好地帮助你处理生活和工作上的事情。也正因如此,我才整理了10句编程谚语,每位开发人员都应该铭记他们,武装自己。

1. 无风不起浪



别紧张,这也许只是一场消防演习

代码设计是否糟糕,从某些地方就可以看出来。比如:

a. 超大类或超大函数

b. 大片被注释的代码

c. 逻辑重复

d. If/else嵌套过深

程序员们通常称它们作代码异味(Code Smell),但是就我个人认为“代码警报”这个名字更为合适一些,因为它有更高的紧迫感的含义。根本问题处理不当,终将引火烧身。
译注:Code Smell中文译名一般为“代码异味”,或“代码味道”,它是提示代码中某个地方存在错误的一个暗示,开发人员可以通过这种smell(异味)在代码中追捕到问题。

2. 预防为主,治疗为辅



好吧,我相信了!

20世纪80年代,丰田公司的流水作业线因为它在缺陷预防方法上的革新变得出了名的高效。每个发现自己的部门有问题的成员都有权暂停生产。这个方法意在宁可发现问题后马上暂定生产、解决问题,也不能由其继续生产而导致更棘手且更高代价的修复/更换/召回后的问题。

程序员总会做出生产率就等同于快速编码的错误臆断。许多程序员都会不假思索地直接着手代码设计。可惜,这种Leeroy Jenkins式鲁莽的做法多会导致软件的开发过程变得很邋遢,拙劣的代码需要不断的监测和修改——也可能会被彻底地替换。最终,生产率所涉及到的因素就 不仅仅是写代码所消耗的时间了,还要有调试的时间。稍不留神就会“捡了芝麻丢了西瓜”。(因小失大。)

译注:Leeroy Jenkins 行为:WOW游戏中一位玩家不顾大家独身一人迎敌,导致灭团。

3. 不要孤注一掷 (过度依赖某人)

一个软件开发团队的公共要素(bus factor)是指那些会影响整个项目进程的核心开发人员的总数。比如某人被车撞了或某人生孩子或某人跳槽了,项目可能就会无序,甚至会搁置。

译注: bus factor 即指公共要素,比喻了开发过程中的一些共同因素。如果挤上 bus 的 factor 越多,bus 就越不稳定,所以要控制好 bus factor ,以免问题发生。

换句话说,如果你的团队突然失去了一个主力成员,你会怎么办?生意依旧进行还是戛然而止?

很不幸,大多数软件团队都陷入了后一种情况。这些团队把他们的开发员培养成了只会处理他们自己专业领域的“领域专家”。起初,这看起来是一个比较合 理的方法。它 对汽车制造装配生产线很适用,但是为什么对软件开发团队就不行呢?毕竟,想让每个成员都掌握所编程序的细微差别也不太可能,对吧?

问题是开发人员不容易轻易替换掉。虽然当每位成员都可用时,“抽屉方法”很有效,但如果当“领域专家”突然因人事变动、疾病或突发事故而无法工作 时,抽屉 方法立马土崩瓦解。(所以,)软件团队有一些看似多余实则重要的后备力量是至关重要。代码复查、结对编程和共有代码可用成功营造一个环境,在这个环境中, 每位开发人员至少表面上是熟悉自己非擅长领域之外的系统部分。

4. 种瓜得瓜,种豆得豆



《注重实效的程序员》一书中有这样一段话解释“破窗理论”:不要留着“破窗户”(低劣的设计、错误的决策或者糟糕的代码)不修。发现一个就修一个。 如果没有足够的时间进行适当的修理,就先把它保留起来。或许你可 以把出问题的代码放到注释中,或是显示“未实现”消息,或用虚拟数据加以替代。采取一些措施,防止进一步的恶化。这表明局势尚在掌控之中。

我们见过整洁良好的系统在出现“破窗”之后立马崩溃。虽然促使软件崩溃的原因还有其他因素(我们将在其他地方接触到),但(对“破窗”)置之不理,肯定会更快地加速系统崩溃。

简而言之,好的代码会促生好的代码,糟糕的代码也会促生糟糕的代码。别低估了惯性的力量。没人想去整理糟糕的代码,同样没人想把完美的代码弄得一团糟。写好你的代码,它才更可能经得住时间的考验。

译注:《注重实效的程序员》,作者Andrew Hunt / David Thomas。该书直击编程陈地,穿过了软件开发中日益增长的规范和技术藩篱,对核心过程进行了审视――即根据需求,创建用户乐于接受的、可工作和易维护 的 代码。本书包含的内容从个人责任到职业发展,直至保持代码灵活和易于改编重用的架构技术。从本书中将学到防止软件变质、消除复制知识的陷阱、编写灵活、动 态和易适应的代码、避免出现相同的设计、用契约、断言和异常对代码进行防护等内容。

译注:破窗理论(Broken Window theory):是关于环境对人们心理造成暗示性或诱导性影响的一种认识。“破窗效应”理论是指:如果有人打坏了一幢建筑物的窗户玻璃,而这扇窗户又得不 到及时的维修,别人就可能受到某些暗示性的纵容去打烂更多的窗户。发现问题就要及时矫正和补救。

5. 欲速则不达

经理、客户和程序员正日益变得急躁。一切都需要做的事,都需要马上就做好。正因如此,快速修复问题变得非常急迫。

没时间对一个新功能进行适当的单元测试?好吧,你可以先完成一次测试运行,然后你就可以随时回来继续测试它。

当访问Y属性时,会不会碰到奇怪的对象引用错误?无论怎样,把代码放到try/catch语句块中。我们要钓到大鱼啦!

是不是似曾相识呢?这是因为我们在以前已经都做到了。并且在某些情况下、它是无可非议的。毕竟,我们有最后期限,还得满足客户和经理。但不要过于频 繁操 作,否则你会发现你的代码不稳定,有很多热修复、逻辑重复、未测试的方案和错误处理。最后,你要么是把事情草草做完,要么是把事情好好做完。

6. 三思而后行

“敏捷开发”这个词最近被频繁滥用,经常被程序员用来掩饰他们在软件开发过程中的糟糕规划/设计阶段。我们是设计者,看到产品朝正当方向有实质进 展,我们理应高兴。但意外的是,UML图和用例分析似乎并不能满足我们的愿望。所以,在不知自己做什么的情况下或者不知自己身处何处时,我们开发人员经常 就稀里糊涂地写代码了。

这就好比你要去吃饭,但你根本没有想好去哪里吃。因为你太饿了,所以你迫不及待地找个餐馆,定个桌位。然后你上车开车后沿途在想(找地方吃饭)。只 是,这样会耗费更多的时间,因为你要过较多的U型弯道,还在餐馆前停车,也许最后因等待时间过长而不吃了。确切地说,你最后应该能找到地方吃饭,但你可能 吃的饭并不是你想吃的,并且这样花费的时间,可能比你直接在想去的餐馆订餐所花的时间更长。

7. 如果你惟一的工具是一把锤子,你往往会把一切问题看成钉子



看见了吧?我早就说过动态记录在这个项目中很有效

程序员有一种倾向,当一谈到他们工具时,其视野就变狭窄了。一旦某种方法在我们的一个项目上“行得通”,我们就会在接下来所有的项目上都用到它。学 习新东 西仿佛是一种煎熬,有时候甚至会心神不定。从始至终都在想“如果我用之前的方法做、这个就不会这么麻烦了”。一定要摒弃这种想法,按我们所知道的去做,即 使那不是最完美的解决方法。

坚持自己所知很简单,不过从长远的角度讲,选择一个适合这项工作的工具要容易得多。否则,就会与你的职业生涯格格不入。

8. 沉默即赞同



我什么都没看见!没看见!

“破窗理论”与“变成惯性理论”有着宏观的联系。

编程社区就好像一个现实社区。每个作品都是一个开发者的缩影。糟糕的代码发布的越多,就越容易反映现状。如果你不去努力编写优秀、整洁和稳定的代码,那你每天都将和糟糕的代码相伴了。

同样地,如果你看到别人写出了糟糕的代码,你就要跟这个人提出来。注意,这时候机智就应该用上场了。一般情况下,程序员都愿意承认他们在软件开发中还是有不懂的地方,并且会感谢你的好意。互相帮助对大家都有利,而对问题视而不见,只会使问题一直存在。

9. 双鸟在林,不如一鸟在手

如果可以讨论系统架构和重构,那么就差找个时间把事情做完。为了使正常运作的东西更加简洁而做改动,权衡改动的利弊很重要。当然了,简洁是一个理想 目标, 但总会有可以通过重构改进的代码。在编程世界中,为了代码不过时,会频繁简单改动代码。但有时候你又必须保证代码对客户有价值。那么,你面临一个简单窘 境:你不能一石二鸟。你在重构旧代码上所发时间越多,你编写新代码的时间就越少。在及时改进代码和维护程序之间,也需要找到平衡点。

10. 能力越大,责任越大



毫无疑问,软件已成为我们生活中一个既基本又重要的一部分。正因如此,开发优秀软件格外重要。乒乓球游戏中的Bug是一回事,航天飞机导向系统或者 航空交通管制系统中的Bug是另外一回事。Slashdot曾发表一文,讲述了单单Google News的一个小失误使一家公司股票蒸发11.4亿美元。其他例子参见《软件Bug引发的十次严重后果》。这些例子便说明了我们正行使着多大的权利。你今 天写的代码,无论你是否有意,说不定有朝一日在重要的应用程序中派上用场,这想想都令人害怕。编写正确合格的代码吧!

英文链接:10 Programming Proverbs Every Developer Should Know

译文链接:10句编程箴言,每个程序员都应该知道

Friday, February 4, 2011

利用 Selenium 自动化 web 测试

http://www.ibm.com/developerworks/cn/opensource/os-webautoselenium/#ibm-pcon

简介


Selenium 是一个健壮的工具集合,跨很多平台支持针对基于 web 的应用程序的测试自动化的敏捷开发。它是一个开源的、轻量级的自动化工具,很容易集成到各种项目中,支持多种编程语言,比如 .NET、Perl、Python、Ruby 和 Java™ 编程语言。



利用 Selenium 测试 Ajax 应用程序


Asynchronous
JavaScript and XML (Ajax) 是一种用于创建交互式 web 应用程序的 web 开发技术。Ajax 应用程序的一个特征是,不会导致一次重新加载整个页面。相反,浏览器将具有一个对服务器的异步调用以获得数据,并且只刷新当前页面的特定部分。要提高 web 页面的交互性、响应速度和可用性,测试 Ajax 应用程序的过程需要一些改变。


我们首先刷新 web 页面,然后就是等待,直到异步调用完成。完成之后,可以继续进行验证。此时,出现适当等待时间的问题。


一种选择是在测试应用程序中简单地暂停一段固定的时间,这在大多数情况下都是可行的。在有些情况下,比如说网络吞吐量很慢时,Ajax 调用在暂停一段特定的时间之后没有完成,会导致测试用例失败。另一方面,如果暂停时间太长,会使得测试慢得不可接受。


Selenium 提供了更为高效的处理等待的方式。一种可能做法是,使用类 com.thoughtworks.selenium.Wait 来等待一个元素或文本在页面上出现或消失。可以在 until() 函数中定义等待的退出条件,或者扩展 Wait 类来实现等待退出。清单 1 是使用 Wait 类的样例代码。它将在条件满足时停止等待,或者在超出最大等待时间时返回一个超时异常。



清单 1. 等待元素或文本出现
    
Wait wait = new Wait() {
public boolean until() {
return selenium.isElementPresent(locator);
// or selenium.isTextPresent(pattern);
}
};
wait.wait("", timeoutInMilliseconds);


另一种选择是使用 Selenium 中的 waitForCondition 函数,一个 JavaScript 代码片段将被作为参数传递给该函数。一旦 Selenium 检测到条件返回为真,它将停止等待。您可以等待一些元素或文本出现或者不出现。JavaScript 可以运行在由 Selenium.browser.getCurrentWindow() 函数弹出的应用程序窗口中。清单 2 是检查窗口状态的样例代码。它只工作在 Firefox 中。



清单 2. 等待窗口就绪的状态
    
String script = "var my_window = selenium.browserbot.getCurrentWindow();"
script += "var bool;";
script += "var readyState = (my_window.document.readyState);";
script += "if (readyState == 'complete'){";
script += "bool = 'true';";
script += "}";
script += "bool;";
selenium.waitForCondition(script, timeoutInMilliseconds);



如何支持 dojo 应用程序


Dojo 是一个常用的 JavaScript 工具包,用于构造动态 web 界面。使用 Selenium 测试 Dojo 应用程序时的一个关键点是认识 Dojo 小部件和记录它们的操作。作者定义的 Dojo 小部件处于抽象级别。页面运行时,会将 Dojo 小部件转换成基本的 HTML 代码。存在很多由 Dojo 自动生成的 HTML 代码,因此,Dojo 小部件的认识可能与传统 HTML 小部件有些不同。


Dojo 小部件上执行的操作(包括文本字段、按钮复选框和单选按钮)可能与 HTML 小部件相同。但是,Dojo 在组合框上提供的日期选择器和其他额外的小部件可能需要特定的处理。




图 1. Dojo 组合框

展示带几个选项的组合框的屏幕快照




使用 Selenium IDE 来记录图 1 中提供的组合框上选中的操作。单击向下箭头,会出现一个下拉列表。选中第三项 Stack(SWG)。记录的脚本提供在图 2 中。




图 2. Selenium IDE 记录的脚本

展示 Selenium 所记录信息(比如鼠标单击)的屏幕快照




有时,只会由 IDE 生成第二行脚本。在这种情况下,添加单击箭头按钮的操作。对于上面的脚本,如果第一行被重新播放,那么它应该生成下拉列表。但是它不执行任何操作。对于多个 Dojo 小部件,单击并不真正执行单击操作。将 click(locator) 更改为 clickAt(locator, coordString) 或者
MouseDown(locator)
MouseUp(locator)。


对于下拉列表,等待时间应该相加。像图 2 中展示的脚本一样,选中项的单击操作将会刚好在单击向下箭头按钮之后执行。它可能会因为下拉列表没有出现而失败。简单地添加一个 pause 命令,或者使用 waitFor 命令等待菜单项元素出现,并继续执行下一个命令。


修改后的将会自动化 Dojo 组合框上的选择的脚本展示在图 3 中。




图 3. 修改后的在 Dojo 组合框中进行选择的 IDE 脚本

屏幕快照展示 clickAt、waitForElement 和 ClickAt 命令已修改




RC 代码展示在清单 3 中。



清单 3. 自动化 Dojo 组合框中选择操作的 RC 代码
    
selenium.clickAt("//div[@id='widget_offeringType']/div/div",””);
selenium.waitForCondition("selenium.isElementPresent(\"offeringType_popup2\")", "2000");
selenium.clickAt("offeringType_popup2",””);




图 4. 日期选择器

展示日期选择器的常规月历视图的屏幕快照




对于图 4 中的日期选择器例子,执行的操作可能不会被 IDE 记录。编写如下面清单 4 所示的 RC 代码。



清单 4. 自动化选择的 RC 代码
    
//click on the date field by id you defined;
selenium.clickAt("dateBox","");
//wait for the drop down date box by id;
selenium.waitForCondition("selenium.isElementPresent(\"widget_dateBox_dropdown\")", \
"2000");
//click previous year 2008;
selenium.clickAt("//span[contains(@class,'dijitCalendarPreviousYear')]", "");
//click on the month increase;
//previous month would contains ‘dijitCalendarIncrease’.
selenium.clickAt("//img[contains(@class,'dijitCalendarIncrease')]","");
//click on the date such as 28 of current month; If you do not specify
//the td with the attribute of current month class, it will click \
on the //first 28 of previous month;
selenium.click("//td[contains(@class,'dijitCalendarCurrentMonth')]/span[text()='28']");


如本例所示,Dojo 应用程序不能通过简单的 IDE 记录进行测试。这些脚本有可能不能通过测试。脚本中有一些丢失的操作,或者操作并不真正工作。脚本应该调整成能够在 IDE 和 RC 中顺利地执行。对于复杂的 Dojo 小部件,一种可能的解决方案是使用 runScript(String) 函数,因为 Selenium 对 JavaScript 提供很好的支持。清单 5 提供一个 JavaScript 语句来模拟组合框选择。



清单 5. 运行 JavaScript 语句在组合框上进行选择
    
selenium.runScript("dijit.byId(\"offeringType\").setValue(\"Stack(SWG)");");



如何利用 Ant 构建 Selenium 测试


诸如 Ant 这样的集成工具可以方便地构建 Selenium 测试和顺畅地运行测试用例,无需单独启动 Selenium 服务器。如果 Selenium 测试由 TestNG 驱动,那么定义清单 6 所示 TestNG Ant 任务。清单 6 中假设 classpath 是 TestNG.jar 文件的文件路径。



清单 6. TestNG Ant 任务
    
<taskdef resource="testngtasks" classpath="testng.jar"/>


主要的目标是启动服务器、运行测试,然后停止服务器。这些任务按照 bulid.xml 中定义的顺序实现在清单 7 中。



清单 7. 启动服务器、运行测试用例并停止服务器的 Ant 任务
    
<target name="run_test" description="start,run and stop" depends="dist">
<parallel>
<antcall target="start-server" />
<sequential>
<echo taskname="waitfor" message="Waitforproxy server launch" />
<waitfor maxwait="2" maxwaitunit="minute" checkevery="100">
<http url="http://localhost:4444/selenium-server/driver/?cmd=testComplete" />
</waitfor>
<antcall target="runTestNG" />
<antcall target="stop-server" />
</sequential>
</parallel>
</target>


代码更可取的地方是使用 waitfor 任务来测试 Selenium 服务器是否已成功启动,而不是暂停一段固定的时间。如果 URL http://localhost:4444/selenium-server/driver/?cmd=testComplete
可用,就意味着 Selenium 已经成功启动。在清单 7 中,它最多等待两分钟,并且每 100 毫秒在本地主机上检查一次 Selenium 服务器,以提供完整的 URL。


start-server 任务的详细内容定义在清单 8 中。Firefox profile 模板位置和其他参数可以指定在标记 <arg> 中。



清单 8. 详细的启动服务器的 Ant 任务
    
<target name="start-server">
<java jar="lib/selenium-server.jar" fork="true">
<arg line="-firefoxProfileTemplate ${selenium}/profile/" />
</java>
</target>


runTestNG 任务的详细内容定义在清单 9 中。testng
任务的常用属性包括 outputDirxmlfileset。属性 outputDir 用于设置输出报告位置。属性 xmlfileset 用于包含启动 XML 文件。更多选项请参考 TestNG 正式网站。



清单 9. 运行测试用例的 Ant 任务
    
<target name="runTestNG">
<testng outputDir="${testng.report.dir}" sourcedir="${build}"
classpathref="run.cp" haltOnfailure="true">
<xmlfileset dir="${build}" includes="testng.xml" />
</testng>
</target>


stop-server 任务的详细内容定义在清单 10 中。



清单 10. 停止 Selenium 服务器的 Ant 任务
    
<target name="stop-server">
<get taskname="selenium-shutdown"
src="http://localhost:4444/selenium-server/driver/?cmd=shutDown" ignoreerrors="true" />
<echo taskname="selenium-shutdown" message=" Errors during shutdown are expected" />
</target>


上面列出了关键任务。将它们组合到您的构建文件,以便利用 Ant 完成良好集成的测试。



如何支持测试 HTTPS 网站


随着互联网日益强调信息安全,越来越多的 web 应用程序在使用 SSL 身份认证。Selenium IDE 默认支持 HTTPS,但是 Selenium RC 不是这样的。Internet
Explorer 和 Firefox 中的解决方案各不相同。


对于 IE,在 setup 目录下的 SSL 支持文件夹中在安装一个证书。如果使用的版本早于 Selenium-RC 1.0 beta 2,请使用 *iehta 运行模式,对于 Selenium-RC 1.0 beta 2 或更晚的版本,使用 *iexplore 运行模式。


如果测试 HTTPS 网站时出现一个如下所示的安全警告,那么单击 View Certificate 并安装 HTTPS 网站的证书。如果继续弹出警告,那么考虑在 IE 中进行配置。打开 Tool > Internet Options > Advanced,并取消选择 security 分类下的 Warn about invalid site certificatesCheck for
publisher's certificate revocation




图 5. 测试 HTTPS 网站时的安全警告

展示指出证书未证实的 Security Alert 的屏幕快照




创建新的 Firefox 配置文件


对于 Firefox,遵循以下步骤创建定制的配置文件,然后重启服务器:



  1. 关闭任何正在运行的 Firefox 实例。

  2. 利用配置文件管理器 firefox
    -ProfileManager
    启动 Firefox。

  3. 创建一个新的配置文件。出现提示时,为配置文件选择一个目录。将它放在项目文件夹里面。

  4. 选择配置文件并运行 Firefox。

  5. 利用您将用于测试的自签名证书导航到 HTTPS URL。 出现提示时接受证书。这将在配置文件中创建一个异常。

  6. 关闭浏览器。

  7. 转到 Firefox 配置文件目录。

  8. 删除该目录中除 cert_override.txtcert8.db 文件之外的任何东西。


默认情况下,Selenium 将在启动 Firefox 的实例时创建一个新的配置文件。当您利用参数 -firefoxProfileTemplate /path/to/profile/dir 启动服务器时,Selenium 将使用一个部分配置文件(带有证书异常)作为创建新配置文件的基础。这将提供证书异常,而避免了使用整个配置文件带来额外的混乱。注意一下在 Selenium RC 1.0 Beta 2 或更晚版本中以 *firefox 模式,以及在 Selenium RC 1.0
Beta 2 之前的版本中以 *chrome 模式启动 Firefox。

对于运行模式,*chrome
*iehta 是较早版本 Selenium RC 中支持 HTTPS 和安全弹出处理的实验模式。自 Selenium-RC 1.0 beta 2 起,它们已经稳定成 *firefox*iexplore 运行模式。请谨慎地根据所使用的 Selenium 版本而使用运行模式。



如何高效地认识不带 ID 属性的 web 元素


使用一个有含义的 ID 或名称是一种高效且方便的定位元素的方式。它也可以改善测试用例的可读性。但是为了每个元素具有一个有含义的、惟一的 ID(尤其是动态元素),Selenium 提供多种策略来认识元素,比如说 Xpath、DOM 和 CSS。


下面是一个样例,使用三种策略来定位图 6 中提供的动态表格中的一个元素。HTML
代码在清单 11 中。




图 6. 动态表格样例

展示动态创建的简单表格(带有两列和编辑链接)的屏幕快照





清单 11. 第一个表格列的 HTML 代码
    
<table id="test_table" border="1">
<tbody>
<tr>
<td align="left">
<div class="test_class">Test 1</div>
</td>
<td align="center" style="vertical-align: top;">
<table id="AUTOGENBOOKMARK_4">
<tbody>
<tr>
<td align="center" style="vertical-align: top;">
<div>
<img alt="supported" src="supported.png"/>
</div>
</td>
<td align="center" style="vertical-align: top;">
<div>
<a href="test?name=test1">edit</a>
</div>
</td>
…….


Xpath
是一种找到不带特定 ID 或名称的元素的简单方式。



  • 如果知道 ID 或名称之外的一个属性,那么直接使用 @attribute=value 定位元素。

  • 如果只知道属性值的一些特定部分,那么使用 contains(attribute, value) 定位元素。

  • 如果元素没有指定的属性,那么利用 Firebug 搜索最近的具有指定属性的父元素,然后使用 Xpath 从这个元素开始定位想要找到的那个元素。



表 1. 定位元素的 Xpath 表达式


定位元素

Xpath 表达式
n 行的第一列
//table[@id='test_table']//tr[n]/td
n 行的图像
//table[@id='test_table']//tr[n]//img
‘Test 1’ 的编辑链接
//a[contains(@href,test1)]


表 1 展示了定位元素的 Xpath 表达式。在 Firebug 的帮助下,Xpath 可以定位元素和复制的元素。在元素没有 ID 和名称时,Selenium IDE 将会采用 Xpath。尽管 Xpath 利用已经录的脚本,有助于保持一致性,但是它高度依赖于 web 页面的结构。这使得测试用例可读性差,增加了维护难度。此外,在 Internet Explorer 7 和 Internet
Explorer 8 中运行具有多个复杂 Xpath 表达式的测试用例可能会太慢了。在这种情况下,将 Xpath 更换为 DOM,后者是另一种高效的定位策略。


DOM 是 Document Object Model(文档对象模型)的缩写。Selenium 允许您利用 JavaScript 遍历 HTML DOM。Java 的灵活性允许在 DOM 表达式中有多个语句,用分号隔开,以及在语句中定义函数。



表 2. 定位元素的 DOM 表达式


定位元素

DOM 表达式
n 行的第一列
dom=document.getElementById('test_table').rows[n-1].cells[0]
n 行的图像

dom=element=document.getElementById('test_table').rows[n-1].cells[1];
element.getElementsByTagName('IMG')[0]

‘Test 1’ 的编辑链接
dom=function test(){
var array=document.getElementsByTagName('a');
var element;for(var i=0; i<array.length; i++)
{if(array[i].attributes.getNamedItem("href").\
value.indexOf('test2')!=-1){element=array[i];break;}}return element}; test()




表 2 展示了定位元素的 DOM 表达式。DOM 定位器在 Firefox 和 Internet Explorer 中也有很好的性能。组织 DOM 表达式需要一些 JavaScript 知识。有时,DOM 表达式对于复杂的元素来说太长了,难以看懂(参见表 2 中提到的 Test 1 的编辑链接的表达式)。


CSS 定位器用于利用 CSS 选择器选择元素。当 HTML 代码具有良好的样式时,可以高效地利用 CSS 定位器。样例表达式展示在表 3 中。



表 3. 定位元素的 CSS 表达式


定位元素

CSS 表达式
n 行的第一列
css=#test_table
.test_class:nth-child(n)

n 行的图像
css=#test_table  tr:nth-child(n) > td:nth-child(2) >
table td:nth-child(1) > div > img


‘Test 1’ 的编辑链接
css=a[href*='test2']


一般来说,选用熟悉的定位器表达式,并在脚本结构中保持一致。如果有多种表达式可执行,那么使用最高效的方式在 web 页面中定位元素。



如何处理弹出窗口


一般来说,操作都是在由 Selenium 启动的主窗口中执行。如果您想在一个由 window.open
函数生成的新窗口中执行操作,那么将焦点更换到新窗口。在弹出窗口中执行操作之后,焦点返回到主窗口。处理弹出窗口的过程定义在清单 12 中。



清单 12. 处理弹出窗口的样例代码
    
//wait for the popup window with timeout;
selenium.waitForPopUp(windowname, timeout);
//select the pop up window
selenium.selectWindow(popupWindowIdentifier);
//perform action on popup window and close the window;
....
//return to the main window use 'null'
selenium.selectWindow(null);


windowname 是调用 window.open 函数的第二个参数。上面提到的 popupwindowIdentifier 是一个窗口标识符,可以是窗口 ID、窗口名称、title=the title of the windowvar=javascript variable。如果弹出窗口的属性未知,但是真的定义了,那么使用 getAllWindowIds()getAllWindowNames()getAttributeFromAllWindows() 函数来检索弹出窗口的属性。


在最新版的 Selenium
RC 1.0.1 中,Selenium 添加了像 selectPopUp(String)deselectPopUp() 这样的方法,它们的功能在以前版本中由 selectWindow(String) 提供。



清单 13. 处理弹出窗口的弹出函数
    
//wait for the popup window with timeout;
selenium.waitForPopUp(“”, timeout);
//same as selenium.selectWindow
selenium.selectPopUp(“”);
//perform action on popup window and close the window;
....
//same as selenium.selectWindow(null);
selenium.deselectPopUp();


清单 13 展示了处理弹出窗口最简单的方式。您可以保留 waitForPopUp
selectPopUp 函数中的第一个参数为空。如果同时弹出多个窗口,请指定窗口属性。



如何处理上载/下载文件窗口


Selenium 使用 JavaScript 来模拟操作。因此,它不支持诸如上载窗口、下载窗口或身份认证窗口之类的浏览器元素。对于非主要窗口,配置浏览器跳过弹出窗口。




图 7. 安全信息窗口

展示 Security Information 弹出窗口的屏幕快照,指出页面包含安全的和不安全的条目




跳过图 7 中安全信息窗口的解决方案是打开 Tools > Internet Options > Custom Level。然后启用 Display mixed content


配置 Internet Explorer 跳过非主要窗口会减少或消除运行测试用例时不必要的处理。但是如果配置了 Firefox,那么将它保存为新的配置文件,并利用定制的配置文件启动服务器。在关于测试 HTTPS 网站的一节中提到了这样做的原因。


对于上载/下载窗口,最好是处理而不是跳过它们。为了避免 Selenium 的局限性,一种建议是使用 Java 机器人 AutoIt 来处理文件上载和下载问题。AutoIt 被设计来自动化 Window GUI 操作。它可以认识大多数 Window GUI,提供很多 API,并且很容易转换为 .exe 文件,这样的文件可以直接运行或者在 Java 代码中调用。清单 14 演示了处理文件上载的脚本。这些脚本的步骤是:



  1. 根据浏览器类型确定上载窗口标题。

  2. 激活上载窗口。

  3. 将文件路径放入编辑框中。

  4. 提交。



清单 14. 处理上载的 AutoIt 脚本
    

;first make sure the number of arguments passed into the scripts is more than 1
If $CmdLine[0]<2 Then Exit EndIf
handleUpload($CmdLine[1],$CmdLine[2])

;define a function to handle upload
Func handleupload($browser, $uploadfile)
Dim $title ;declare a variable
;specify the upload window title according to the browser
If $browser="IE" Then ; stands for IE;
$title="Select file"
Else ; stands for Firefox
$title="File upload"
EndIf

if WinWait($title,"",4) Then ;wait for window with
title attribute for 4 seconds;
WinActivate($title) ;active the window;
ControlSetText($title,"","Edit1",$uploadfile) ;put the
file path into the textfield
ControlClick($title,"","Button2") ;click the OK
or Save button
Else
Return False
EndIf
EndFunc


在 Java 代码中,定义一个函数来执行 AutoIt 编写的 .exe 文件,并在单击 browse 之后调用该函数。



清单 15. 执行 AutoIt 编写的 .exe 文件
    

public void handleUpload(String browser, String filepath) {
String execute_file = "D:\\scripts\\upload.exe";
String cmd = "\"" + execute_file + "\"" + " " + "\"" + browser + "\""
+ " " + "\"" + filepath + "\""; //with arguments
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor(); //wait for the upload.exe to complete
} catch (Exception e) {
e.printStackTrace();
}
}


清单 16 是处理 Internet Explorer 中下载窗口的 AutoIt 脚本。Internet Explorer 和 Firefox 中的下载脚本各不相同。



清单 16. 处理 Internet Explorer 中下载的 AutoIt 脚本
    

If $CmdLine[0]<1 Then Exit EndIf
handleDownload($CmdLine[1])
Func handleDownload($SaveAsFileName)
Dim $download_title="File Download"
If WinWait($download_title,"",4) Then
WinActivate($download_title)
Sleep (1000)
ControlClick($download_title,"","Button2","")
Dim $save_title="Save As"
WinWaitActive($save_title,"",4)
ControlSetText($save_title,"","Edit1", $saveAsFileName)
Sleep(1000)
if FileExists ($SaveAsFileName) Then
FileDelete($SaveAsFileName)
EndIf
ControlClick($save_title, "","Button2","")
Return TestFileExists($SaveAsFileName)
Else
Return False
EndIf
EndFunc


AutoIt 脚本很容易编写,但是依赖于浏览器类型和版本,因为不同的浏览器和版本中,窗口标题和窗口控件类是不相同的。



如何验证警告/确认/提示信息


对于由 window.alert() 生成的警告对话框,使用 selenium.getAlert() 来检索前一操作期间生成的 JavaScript 警告的消息。如果没有警告,该函数将会失败。得到一个警告与手动单击 OK 的结果相同。


对于由 window.confirmation() 生成的确认对话框,使用 selenium.getConfirmation() 来检索前一操作期间生成的 JavaScript 确认对话框的消息。默认情况下,该函数会返回 true,与手动单击 OK 的结果相同。这可以通过优先执行 chooseCancelOnNextConfirmation 命令来改变。


对于由 window.prompt() 生成的提示对话框,使用 selenium.getPromt() 来检索前一操作期间生成的 JavaScript 问题提示对话框的消息。提示的成功处理需要优先执行 answerOnNextPrompt 命令。


JavaScript 警告在 Selenium 中不会弹出为可见的对话框。处理这些弹出对话框失败会导致异常,指出没有未预料到的警告。这会让测试用例失败。





参考资料

学习

获得产品和技术

讨论


作者简介

Zhang Chao Chao 是 IBM China Development Lab 的一名软件测试工程师。她具有敏捷测试和测试自动化方面的经验。

作者照片

Peng Cheng Yu 是 IBM 中国开发实验室的一名软件工程师。他在一些全球化项目中是测试负责人,在敏捷测试、质量保证和测试自动化方面拥有丰富经验。