发布新日志

  • 在Linux平台上安装和配置Redhat系列下安装rubyOnRails的生产环境(转)

    2010-07-15 17:00:27


    转发:http://docs.google.com/View?id=dc32cxpz_105hqdqknhq

    简 单描述

    这里介绍的内容是基于redhat系列(rhel或者centos)的。由于各个发行版的情况都有不一样的地方,如果使用的是其他发行版本请自行 google。另外我测试的环境是gcc4.x,这里使用的数据库是oracle,mysql的内容以后再加。 主要软件及用途如下:
    ruby1.8.7-p72-mbari(ruby解释器,用来解释ruby语言用的)
    rails2.1.2(一个用ruby写的一站式快速开发框架)
    oracle10g(数据库)
    ruby- oci8(用来和oracle交互用的ruby库)
    ruby-odbc(用来 和odbc交互用的ruby库)
    RMagick(图形处理库)
    memcached(流行的分布式缓存服务器)
    lighttpd/nginx(web前端服务器)
    mongrel/thin(用 来处理动态请求的http服务器)
    fcgi(fast cgi运行模块) 一般是使用多进程单线程的运行方式,部署在lighttpd+fcgi(非常高效,安装麻烦),或者nginx+mongrel/thin(高效,安装简 单)的架构上。

    安 装ruby

    http://www.javaeye.com/wiki/rails_deployment/1296-deploy-rails-on-linux
    http://www.javaeye.com/news/4592-resolve-memory-leaks-ruby-patch-release
    下载ruby 1.8.7-p72.tar.gz和MBARIp72patches.tar.gz
    tar zxvf ruby-1.8.7-p72.tar.gz
    tar zxvf MBARIp72patches.tar.gz
    解压打补丁命令:
    MBARIp72patches/apply ruby-1.8.7-p72
    编译ruby,如下:
    cd ruby-1.8.7-p72
    CFLAGS="-O2 -fno-stack-protector -mpreferred-stack-boundary=2" ./configure --prefix=/usr/local/ruby-1.8.7-p72
    make && make install
    备注:如果没有gcc,需要yum install gcc,如果是gcc3.x,需要去掉-fno-stack-protector

    编译之后,编辑/etc/profile,加入

          export RUBY_HOME=/usr/local/ruby-1.8.7-p72
          PATH=$RUBY_HOME/bin:$PATH

    执 行source /etc/profile,并使用ruby -v进行验证:

    [root@localhost ext]# ruby -v
    ruby 1.8.7 (2009-3-1 mbari 8B/0x8770 on patchlevel 72) [i686-linux]

    下 载rubygems-1.3.1.tgz

    tar zxvf rubygems-1.3.1.tgz
    cd rubygems-1.3.1
    ruby setup.rb
    并使用gem -v进行验证:
    [root@localhost ext]# gem -v
    1.3.1

    安 装ruby-ext:zilb,readline或者openssl

    cd ruby-1.8.7-p72/ext/zlib
    ruby extconf.rb --with-zlib-include=/usr/include --with-zlib-lib=/usr/lib
    make && make install 如果出错,可能需要进行yum install zlib-devel
    cd ruby-1.8.7-p72/ext/readline
    ruby extconf.rb
    make && make install 如果出错,可能需要进行yum install readline-devel
    cd ruby-1.8.7-p72/ext/openssl
    ruby extconf.rb
    make && make install 如果出错,可能需要进行yum install openssl-devel

    安 装各式各样的gem

    gem source -a http://gems.github.com

    gem install rails --version "2.1.2" --no-rdoc --no-ri
    gem install mongrel_cluster --no-rdoc --no-ri
    gem install memcache-client --version "1.7.3" --no-rdoc --no-ri
    yum install libxml2*
    gem install libxml-ruby --version "1.1.3" --no-rdoc --no-ri
    gem install spreadsheet --version "0.6.3.1" --no-rdoc --no-ri
    gem install uuidtools --version "2.0.0" --no-rdoc --no-ri
    gem install composite_primary_keys --version "1.1.0" --no-rdoc --no-ri
    gem install rack --no-rdoc --no-ri
    gem install thin --no-rdoc --no-ri
    gem install dbi --version "0.4.2" --no-rdoc --no-ri
    gem install dbd-odbc --version "0.2.5" --no-rdoc --no-ri
    备注:如果提示g++命令未找到,则yum install gcc-c++

    安 装oracle即时客户端

    rpm -ivh oracle-instantclient-basic-10.2.0.4-1.i386.rpm
    rpm -ivh oracle-instantclient-devel-10.2.0.4-1.i386.rpm
    可选:
    #rpm -ivh oracle-instantclient-sqlplus-10.2.0.4-1.i386.rpm
    #rpm -ivh oracle-instantclient-jdbc-10.2.0.4-1.i386.rpm

    修改 /etc/profile,添加

    export NLS_LANG="American_America.ZHS16GBK"
    export LD_LIBRARY_PATH=/usr/lib/oracle/10.2.0.4/client/lib
    PATH=$LD_LIBRARY_PATH:$PATH 执行source /etc/profile

    下载ruby-oci8-1.0.6.tar.gz

    tar zxvf ruby-oci8-1.0.6.tar.gz
    cd ruby-oci8-1.0.6
    ruby setup.rb config
    ruby setup.rb setup
    ruby setup.rb install

    验证ruby- oci8安装情况

    [root@localhost i686-linux]# irb
    irb(main):001:0> require 'oci8'
    => true
    如果出错的话(cannot restore segment prot after reloc: Permission denied), 需要执行/usr/sbin/setenforce 0来临时关闭selinux 也可以修改/etc/selinux/config把enforcing修改成disabled并重启

    安装 odbc

    有时候我们需要用到sqlserver这样的东西,在linux上弄这个还是比较麻烦的。我们采取的方案是 unixODBC+freeTDS+ruby-odbc+dbi(dbd-odbc)的方式(我们并不打算使用orm)。首先需要安装的是 freeTDS(*unix下用来访问sybase和sqlserver的工具)和unixODBC(用来提供ODBC,在这里就是利用freeTDS的 驱动来提供一个DSN)
    yum install unixODBC-devel freetds-devel
    安装后可以测试一下
    [root@localhost ~]# tsql -S 192.168.1.233 -U sa -P softsckj
    locale is "zh_CN.UTF-8"
    locale charset is "UTF-8"
    1> use jw
    2> select count(*) from ttuition
    3> go

    262846
    1>
    然后安装ruby- odbc,在http://www.ch-werner.de/rubyodbc/下载ruby-odbc-0.9997.tar.gz
    tar zxvf ruby-odbc-0.9997.tar.gz
    cd ruby-odbc-0.9997
    ruby extconf.rb
    make && make install
    接下去进行配置:
    修改/etc/freetds.conf
    [MyServer2k]
            host = 192.168.1.233
            port = 1433
            tds version = 8.0
    这里修改host,主要是为了可以引用到这个MyServer2K

    修改/etc /odbcinst.ini(这是用来定义各种各样的Driver的地方)
    [FreeTDS]
    Description     = ODBC for MS SqlServer
    Driver          = /usr/lib/libtdsodbc.so
    Setup           = /usr/lib/libtdsS.so
    FileUsage       = 1
    修改/etc /odbc.ini(这里就是配置DSN的地方)
    [JW]
    Description     = jw
    Driver          = FreeTDS
    Servername      = MyServer2k
    Database        = jw
    UID             = sa
    PWD             = softsckj
    注意到这里的MyServer2k引用的是 freetds.conf里边定义的。其实按道理这里直接使用ip就可以的,可惜的是,在freetds0.64里边设置ip的话,根本不起作用。
    最 后,简单写个脚本测试一下:
    [root@localhost ~]# vi test.rb
    #!/bin/env ruby

    require 'rubygems'
    require 'dbi'
    require 'odbc'

    DBI.connect('dbi:ODBC:JW','sa','softsckj') do |dbh|
      dbh.select_all('select top 10 * from ttuition') do |row|
        p row.join(',')
      end
    end
    能够得出结果就表示配置成功了。

    安 装memcached

    下载libevent-1.4.12-stable.tar.gz和memcached-1.4.0.tar.gz tar
    zxvf libevent-1.4.12-stable.tar.gz
    cd libevent-1.4.12-stable
    ./configure --prefix=/usr/local/libevent-1.4.12
    make && make install
    cp /usr/local/libevent-1.4.12/lib/libevent-1.4.so.2 /usr/lib/
    tar zxvf memcached-1.4.0.tar.gz
    cd memcached-1.4.0
    ./configure --with-libevent=/usr/local/libevent-1.4.12 --prefix=/usr/local/memcached-1.4.0
    make && make install

    运行并验证

    [root@localhost bin]# /usr/local/memcached-1.4.0/bin/memcached -d -m 256 -p 11211 -u root
    [root@localhost bin]# telnet localhost 11211
    Trying 127.0.0.1...
    Connected to localhost.localdomain (127.0.0.1).
    Escape character is '^]'.
    stats
    STAT pid 5075
    STAT uptime 155
    STAT time 1248845966
    STAT version 1.4.0

    安 装nginx

    需要其他支持
    yum install pcre-devel openssl-devel
    下载nginx-0.7.61.tar.gz
    tar zxvf nginx-0.7.61.tar.gz
    cd nginx-0.7.61

    ./configure --prefix=/usr/local/nginx-0.7.61 \
      --user=nobody \
      --group=nobody \
      --without-poll_module \
      --with-http_stub_status_module \
      --with-http_gzip_static_module \
      --with-http_realip_module
    \
      --with-http_ssl_module \
      --with-http_flv_module \

      --pid-path=/var/run/nginx.pid \
      --lock-path=/var/lock/nginx.lock \
      --error-log-path=/var/log/nginx/error.log \
      --http-log-path=/var/log/nginx/access.log
    make && make install

    配 置/usr/local/nginx-0.7.61/conf/nginx.conf,示例:

    user nobody;
    worker_processes 1;

    error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;

    #pid logs/nginx.pid;


    events {
      use epoll;
      worker_connections 65535;
    }


    http {
    include mime.types;
    default_type application/octet-stream;

    #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    # '$status $body_bytes_sent "$http_referer" '
    # '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log logs/access.log main;
    access_log off;

    sendfile on;
    #tcp_nopush on;

    #keepalive_timeout 0;
    keepalive_timeout 65;

    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 8k;
    gzip_http_version 1.1;
    gzip_types text/plain application/x-javascript. text/css text/html application/xml image/jpeg image/png image/gif;

    upstream backend {
    server 127.0.0.1:3000 weight=1;
    server 127.0.0.1:3001 weight=1;
    server 127.0.0.1:3002 weight=1;
    server 127.0.0.1:3003 weight=1;
    server 127.0.0.1:3004 weight=1;
    }

    server {
    listen 80;
    server_name localhost;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    #internal;
    proxy_pass http://backend/;
    #proxy_store on;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout 90;
    proxy_send_timeout 90;
    proxy_read_timeout 90;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    index index.html index.php index.htm;
    }

    location /NginxStatus {
    stub_status on;
    access_log on;
    auth_basic "NginxStatus";
    }

    location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
    root /var/www/gst/public;
    index index.php;
    access_log off;
    expires 14d;
    }

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    # proxy_pass http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    # root html;
    # fastcgi_pass 127.0.0.1:9000;
    # fastcgi_index index.php;
    # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
    # include fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    # deny all;
    #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    # listen 8000;
    # listen somename:8080;
    # server_name somename alias another.alias;

    # location / {
    # root html;
    # index index.html index.htm;
    # }
    #}


    # HTTPS server
    #
    #server {
    # listen 443;
    # server_name localhost;

    # ssl on;
    # ssl_certificate cert.pem;
    # ssl_certificate_key cert.key;

    # ssl_session_timeout 5m;

    # ssl_protocols SSLv2 SSLv3 TLSv1;
    # ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    # ssl_prefer_server_ciphers on;

    # location / {
    # root html;
    # index index.html index.htm;
    # }
    #}

    }

    测 试并运行和关闭

    /usr/local/nginx-0.7.61/sbin/nginx -t
    /usr/local/nginx-0.7.61/sbin/nginx -c /usr/local/nginx-0.7.61/conf/nginx.conf&
    killall -HUP nginx

    安 装RMagick

    检测图片支持,如果检测不到的话,需要通过yum来安装
    rpm -qa | grep libpng
    rpm -qa | grep libpng-devel
    rpm -qa | grep libjpeg
    rpm -qa | grep gd-devel
    如果你希望支持tiff格式,还 应该检查
    rpm -qa | grep libtiff
    下载ImageMagick-6.5.4-6.tar.bz2
    tar jxvf ImageMagick-6.5.4-6.tar.bz2

    cd ImageMagick-6.5.4-6
    ./configure --prefix=/usr/local/ImageMagick-6.5.4-6
    make && make install

    编辑/etc/profile里面 的PATH环境变量,加入:

    export PATH=/usr/local/ImageMagick-6.5.4-6/bin:$PATH
    编辑/etc /ld.so.conf,加入: /usr/local/ImageMagick-6.5.4-6/lib
    执 行命令ldconfig将ImageMagick的库加入系统联接库
    执行命令source /etc/profile让文件生效,最后验证 convert logo: logo.gif 看是否正确生成一个logo.gif的图片文件

    下载RMagick-2.10.0.tar.bz2

    tar jxvf RMagick-2.10.0.tar.bz2
    cd RMagick-2.10.0
    ruby setup.rb
    安装完成还是不能使用的话,可以下载rmagick-2.10.0.gem来安装
    gem install rmagick-2.10.0.gem --no-rdoc --no-ri

    安 装fcgi

    由于ruby的fcgi支持库需要在编译的时候联接FCGI的系统库,因此我们需要先安装FCGI库,下载FCGI源代码发行 包:http://www.fastcgi.com/dist/
    tar xzvf fcgi-2.4.0.tar.gz
    cd fcgi-2.4.0
    ./configure --prefix=/usr/local/fcgi-2.4.0
    make && make install

    然 后就可以安装ruby的fcgi支持库了,下载ruby-fcgi-0.8.7.tar.gz

    tar xzvf ruby-fcgi-0.8.7.tar.gz
    cd ruby-fcgi-0.8.7
    ruby install.rb config -- --with-fcgi-dir=/usr/local/fcgi-2.4.0
    ruby install.rb setup
    ruby install.rb install

    在public下面新建 dispatch.sh用来启动fcgi,如下:

    #!/bin/sh

    DISPATCH_PATH=/var/www/gst/public/dispatch.fcgi
    SOCKET_PATH=/tmp
    PID_PATH=/tmp
    RAILS_ENV=production
    export RAILS_ENV

    case "$1" in

    start)
    for num in 0 1 2 3 4 5 6 7 8 9
    do
    /usr/local/lighttpd-1.4.23/bin/spawn-fcgi -f $DISPATCH_PATH -s $SOCKET_PATH/rails$num.sock -P $PID_PATH/rails$num.pid -u lighttpd -g lighttpd
    done
    ;;

    stop)
    killall -9 dispatch.fcgi
    ;;

    restart)
    $0 stop
    $0 start
    ;;

    *)
    echo "Usage: dispatch.sh {start|stop|restart}"
    ;;
    esac
    exit 0
    这样就可以通过./dispatch.sh start来启动10个fcgi进程了,而lighttpd就是把请求交给这10个fcgi进程进行处理的。

    安 装lighttpd

    需要其他支持
    yum install bzip2-devel
    yum install pcre-devel
    yum install gamin-devel
    下载lighttpd-1.4.23.tar.gz
    tar xzvf lighttpd-1.4.23.tar.gz
    cd lighttpd-1.4.23
    ./configure --prefix=/usr/local/lighttpd-1.4.23 --with-fam
    完 毕以后,会给出一个激活的模块和没有激活模块的清单,可以检查一下,是否自己需要的模块都已经激活,在enable的模块中一定要有 “mod_rewrite”这一项,否则重新检查pcre是否安装.最后编译:make && make install 最后把/usr/local/lighttpd-1.4.23/lib添加到/etc/ld.so.conf里边去并执行ldconfig
    cp doc/rc.lighttpd.redhat /etc/init.d/lighttpd
    mkdir /etc/lighttpd
    cp doc/lighttpd.conf /etc/lighttpd/lighttpd.conf
    然后修改/etc/init.d/lighttpd,把
    LIGHTTPD_BIN=/usr/sbin/lighttpd
    改为
    LIGHTTPD_BIN=/usr/local/lighttpd-1.4.23/sbin/lighttpd

    配置/etc/lighttpd/lighttpd.conf,示例:

    # lighttpd configuration file
    #
    # use it as a base for lighttpd 1.0.0 and above
    #
    # $Id: lighttpd.conf,v 1.7 2004/11/03 22:26:05 weigon Exp $

    ############ Options you really have to take care of ####################

    ## modules to load
    # at least mod_access and mod_accesslog should be loaded
    # all other module should only be loaded if really neccesary
    # - saves some time
    # - saves memory
    server.modules = (
    "mod_rewrite",
    # "mod_redirect",
    # "mod_alias",
    "mod_access",
    # "mod_cml",
    # "mod_trigger_b4_dl",
    # "mod_auth",
    # "mod_status",
    # "mod_setenv",
    "mod_fastcgi",
    # "mod_proxy",
    "mod_simple_vhost",
    # "mod_evhost",
    # "mod_userdir",
    "mod_cgi",
    "mod_compress",
    # "mod_ssi",
    # "mod_usertrack",
    # "mod_expire",
    # "mod_secdownload",
    # "mod_rrdtool",
    #"mod_accesslog"
    )


    ## a static document-root, for virtual-hosting take look at the
    ## server.virtual-* options
    server.document-root = "/var/www/gst/public"

    ## where to send error-messages to
    server.errorlog = "/var/log/lighttpd/error.log"

    # files to check for if .../ is requested
    index-file.names = ( "index.php", "index.html",
    "index.htm", "default.htm" )

    ## set the event-handler (read the performance section in the manual)
    # server.event-handler = "freebsd-kqueue" # needed on OS X

    # mimetype mapping
    mimetype.assign = (
    ".pdf" => "application/pdf",
    ".sig" => "application/pgp-signature",
    ".spl" => "application/futuresplash",
    ".class" => "application/octet-stream",
    ".ps" => "application/postscript",
    ".torrent" => "application/x-bittorrent",
    ".dvi" => "application/x-dvi",
    ".gz" => "application/x-gzip",
    ".pac" => "application/x-ns-proxy-autoconfig",
    ".swf" => "application/x-shockwave-flash",
    ".tar.gz" => "application/x-tgz",
    ".tgz" => "application/x-tgz",
    ".tar" => "application/x-tar",
    ".zip" => "application/zip",
    ".mp3" => "audio/mpeg",
    ".m3u" => "audio/x-mpegurl",
    ".wma" => "audio/x-ms-wma",
    ".wax" => "audio/x-ms-wax",
    ".ogg" => "application/ogg",
    ".wav" => "audio/x-wav",
    ".gif" => "image/gif",
    ".jar" => "application/x-java-archive",
    ".jpg" => "image/jpeg",
    ".jpeg" => "image/jpeg",
    ".png" => "image/png",
    ".xbm" => "image/x-xbitmap",
    ".xpm" => "image/x-xpixmap",
    ".xwd" => "image/x-xwindowdump",
    ".css" => "text/css",
    ".html" => "text/html",
    ".htm" => "text/html",
    ".js" => "text/javascript",
    ".asc" => "text/plain",
    ".c" => "text/plain",
    ".cpp" => "text/plain",
    ".log" => "text/plain",
    ".conf" => "text/plain",
    ".text" => "text/plain",
    ".txt" => "text/plain",
    ".dtd" => "text/xml",
    ".xml" => "text/xml",
    ".mpeg" => "video/mpeg",
    ".mpg" => "video/mpeg",
    ".mov" => "video/quicktime",
    ".qt" => "video/quicktime",
    ".avi" => "video/x-msvideo",
    ".asf" => "video/x-ms-asf",
    ".asx" => "video/x-ms-asf",
    ".wmv" => "video/x-ms-wmv",
    ".bz2" => "application/x-bzip",
    ".tbz" => "application/x-bzip-compressed-tar",
    ".tar.bz2" => "application/x-bzip-compressed-tar",
    # default mime type
    "" => "application/octet-stream",
    )

    # Use the "Content-Type" extended attribute to obtain mime type if possible
    #mimetype.use-xattr = "enable"


    ## send a different Server: header
    ## be nice and keep it at lighttpd
    # server.tag = "lighttpd"

    #### accesslog module
    #accesslog.filename = "/var/log/lighttpd/access.log"

    ## deny access the file-extensions
    #
    # ~ is for backupfiles from vi, emacs, joe, ...
    # .inc is often used for code includes which should in general not be part
    # of the document-root
    url.access-deny = ( "~", ".inc" )

    $HTTP["url"] =~ "\.pdf$" {
    server.range-requests = "disable"
    }

    ##
    # which extensions should not be handle via static-file transfer
    #
    # .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
    static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

    ######### Options that are good to be but not neccesary to be changed #######

    ## bind to port (default: 80)
    server.port = 80

    ## bind to localhost (default: all interfaces)
    server.bind = "0.0.0.0"

    ## error-handler for status 404
    #server.error-handler-404 = "/error-handler.html"
    #server.error-handler-404 = "/error-handler.php"

    ## to help the rc.scripts
    server.pid-file = "/var/log/lighttpd/lighttpd.pid"

    server.stat-cache-engine = "fam"
    server.event-handler = "linux-sysepoll"
    server.network-backend = "linux-sendfile"
    server.max-request-size = 10240
    server.max-fds = 2048

    ###### virtual hosts
    ##
    ## If you want name-based virtual hosting add the next three settings and load
    ## mod_simple_vhost
    ##
    ## document-root =
    ## virtual-server-root + virtual-server-default-host + virtual-server-docroot
    ## or
    ## virtual-server-root + http-host + virtual-server-docroot
    ##
    #simple-vhost.server-root = "/srv/www/vhosts/"
    #simple-vhost.default-host = "www.example.org"
    #simple-vhost.document-root = "/htdocs/"


    ##
    ## Format: <errorfile-prefix><status-code>.html
    ## -> ..../status-404.html for 'File not found'
    #server.errorfile-prefix = "/usr/share/lighttpd/errors/status-"
    #server.errorfile-prefix = "/srv/www/errors/status-"

    ## virtual directory listings
    #dir-listing.activate = "enable"
    ## select encoding for directory listings
    #dir-listing.encoding = "utf-8"

    ## enable debugging
    #debug.log-request-header = "enable"
    #debug.log-response-header = "enable"
    #debug.log-request-handling = "enable"
    #debug.log-file-not-found = "enable"

    ### only root can use these options
    #
    # chroot() to directory (default: no chroot() )
    #server.chroot = "/"

    ## change uid to <uid> (default: don't care)
    server.username = "lighttpd"

    ## change uid to <uid> (default: don't care)
    server.groupname = "lighttpd"

    #### compress module
    compress.cache-dir = "/tmp/"
    compress.filetype = ("text/plain", "text/html","text/javascript","text/css")

    #### proxy module
    ## read proxy.txt for more info
    #proxy.server = ( ".php" =>
    # ( "localhost" =>
    # (
    # "host" => "192.168.0.101",
    # "port" => 80
    # )
    # )
    # )

    #### fastcgi module
    ## read fastcgi.txt for more info
    ## for PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini
    #fastcgi.server = ( ".php" =>
    # ( "localhost" =>
    # (
    # "socket" => "/var/run/lighttpd/php-fastcgi.socket",
    # "bin-path" => "/usr/local/bin/php-cgi"
    # )
    # )
    # )

    #### CGI module
    #cgi.assign = ( ".pl" => "/usr/bin/perl",
    # ".cgi" => "/usr/bin/perl" )
    #

    #### SSL engine
    #ssl.engine = "enable"
    #ssl.pemfile = "/etc/ssl/private/lighttpd.pem"

    #### status module
    #status.status-url = "/server-status"
    #status.config-url = "/server-config"

    #### auth module
    ## read authentication.txt for more info
    #auth.backend = "plain"
    #auth.backend.plain.userfile = "lighttpd.user"
    #auth.backend.plain.groupfile = "lighttpd.group"

    #auth.backend.ldap.hostname = "localhost"
    #auth.backend.ldap.base-dn = "dc=my-domain,dc=com"
    #auth.backend.ldap.filter = "(uid=$)"

    #auth.require = ( "/server-status" =>
    # (
    # "method" => "digest",
    # "realm" => "download archiv",
    # "require" => "user=jan"
    # ),
    # "/server-config" =>
    # (
    # "method" => "digest",
    # "realm" => "download archiv",
    # "require" => "valid-user"
    # )
    # )

    #### url handling modules (rewrite, redirect, access)
    #url.rewrite = ( "^/$" => "/server-status" )
    #url.redirect = ( "^/wishlist/(.+)" => "http://www.123.org/$1" )
    #### both rewrite/redirect support back reference to regex conditional using %n
    #$HTTP["host"] =~ "^www\.(.*)" {
    # url.redirect = ( "^/(.*)" => "http://%1/$1" )
    #}

    $HTTP["host"] == "192.168.1.210" {
    server.document-root = "/var/www/gst/public"
    server.error-handler-404 = "/dispatch.fcgi"
    fastcgi.server = (".fcgi" =>
    (
    ("socket"=>"/tmp/rails0.sock"),
    ("socket"=>"/tmp/rails1.sock"),
    ("socket"=>"/tmp/rails2.sock"),
    ("socket"=>"/tmp/rails3.sock"),
    ("socket"=>"/tmp/rails4.sock"),
    ("socket"=>"/tmp/rails5.sock"),
    ("socket"=>"/tmp/rails6.sock"),
    ("socket"=>"/tmp/rails7.sock"),
    ("socket"=>"/tmp/rails8.sock"),
    ("socket"=>"/tmp/rails9.sock")
    )
    )
    }

    #
    # define a pattern for the host url finding
    # %% => % sign
    # %0 => domain name + tld
    # %1 => tld
    # %2 => domain name without tld
    # %3 => subdomain 1 name
    # %4 => subdomain 2 name
    #
    #evhost.path-pattern = "/srv/www/vhosts/%3/htdocs/"

    #### expire module
    #expire.url = ( "/buggy/" => "access 2 hours", "/asdhas/" => "access plus 1 seconds 2 minutes")

    #### ssi
    #ssi.extension = ( ".shtml" )

    #### rrdtool
    #rrdtool.binary = "/usr/bin/rrdtool"
    #rrdtool.db-name = "/var/lib/lighttpd/lighttpd.rrd"

    #### setenv
    #setenv.add-request-header = ( "TRAV_ENV" => "mysql://user@host/db" )
    #setenv.add-response-header = ( "X-Secret-Message" => "42" )

    ## for mod_trigger_b4_dl
    # trigger-before-download.gdbm-filename = "/var/lib/lighttpd/trigger.db"
    # trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" )
    # trigger-before-download.trigger-url = "^/trigger/"
    # trigger-before-download.download-url = "^/download/"
    # trigger-before-download.deny-url = "http://127.0.0.1/index.html"
    # trigger-before-download.trigger-timeout = 10

    ## for mod_cml
    ## don't forget to add index.cml to server.indexfiles
    # cml.extension = ".cml"
    # cml.memcache-hosts = ( "127.0.0.1:11211" )

    #### variable usage:
    ## variable name without "." is auto prefixed by "var." and becomes "var.bar"
    #bar = 1
    #var.mystring = "foo"

    ## integer add
    #bar += 1
    ## string concat, with integer cast as string, result: "www.foo1.com"
    #server.name = "www." + mystring + var.bar + ".com"
    ## array merge
    #index-file.names = (foo + ".php") + index-file.names
    #index-file.names += (foo + ".php")

    #### include
    #include /etc/lighttpd/lighttpd-inc.conf
    ## same as above if you run: "lighttpd -f /etc/lighttpd/lighttpd.conf"
    #include "lighttpd-inc.conf"

    #### include_shell
    #include_shell "echo var.a=1"
    ## the above is same as:
    #var.a=1
  • `gem_original_require': no such file to load -- zlib (LoadError)(转发)

    2010-07-15 13:02:57

    `gem_original_require': no such file to load -- zlib (LoadError)


    转发:http://www.redmine.org/boards/2/topics/10032

    romuald FREBAULT7 个月 之前添加

    I wanted to install redmine on a centos 5.3.
    As ruby 1.6/1.7 packages are not availables on this distribution, i had to download and compile the ruby 1.7 sources.

    I installed rubygems sources

    This error happened when i tried to make a

    gem install rails

    To solve it i had to do a

    yum install zlib-devel 

    then in /opt/ruby/ext/zlib/(即源码目录的ext/zlib下 )

      ruby extconf.rb
    make && make install

    everything is good now!!!

  • JDK1.6在LINUX下的安装配置(转发)

    2010-07-15 10:39:00

    转发:http://soft.preboss.org/?action-viewnews-itemid-589


    JDK1.6在LINUX下的安装是如何进行的呢,让我们开始我们的演示:

    Ubuntu Linux下jdk的安装与配置

    1.JDK1.6安装准备

    从sun公司网站www.sun.com下载linux版本的jdk,我下载的版本是JDK 6 Update 7,

    地址http://java.sun.com/javase/downloads/index.jsp

    jdk-6u7-linux-i586.bin,打开终端,用cd命令进入jdk所在目录,执行复制命令

    sudo cp jdk-6u7-linux-i586.bin /usr

    即将jdk复制到/usr目录下,然后进入/usr目录cd /usr

    执行权限

    chmod +x jdk-6u7-linux-i586.bin

    执行安装命令

    ./jdk-6u7-linux-i586.bin

    如遇错误,可先切换至root用户下,su root,再执行安装命令

    安装成功会在/usr目录下生成jdk1.6.0_07目录,就是jdk的安装目录

    重启电脑,打开终端,输入java -version

    如若有显示java的版本信息,则表示安装成功,

    2.JDK1.6安装后的配置

    安装成功后需要配置jdk环境变量

    用cd命令进入/etc目录sudo vi profile即执行编辑profile文件命令

    在umas k022前添加如下内容:

    export JAVA_HOME=/usr/jdk1.6.0_07

    export JRE_HOME=/usr/jdk1.6.0_07/jre

    export PATH=$PATH:/usr/jdk1.6.0_07/bin

    export CLASSPATH=./:/usr/jdk1.6.0_07/lib:/usr/jdk1.6.0_07/jre/lib

    保存退出,重启电脑

    3.JDK1.6安装配置后的测试

    新建Test.java

    public class Test{

    public static void main(String[] args){

    System.out.println("Hello,Welcome to Linux World!");

    }

    }

    在终端用cd命令进入Test.java目录,然后输入

    javac Test.java

    java Test

    若输出

    Hello,Welcome to Linux World!

    则表明配置成功!

    如不能通过编译,可通过重新启动系统试试

    4.JDK1.6安装配置时的注意事项

    在用vi命令编辑profile文件时,Linux初学者可能还不熟用

    sudo vi profile进入编辑文件后如出现

    Press ENTER or type command to continue

    则按回车然后按方向键“下”直到umas k022前一行

    按字母o进入编辑状态

    输入环境变量内容

    回车,按几次ESC键,直到听到"嘀"声,输入

    :x 然后回车

    即保存退出

    至此,Linux JDK1.6环境变量配置完成,是不是很简单么?开始你的编程之路吧。

  • 在 Ruby on Rails 中进行单元测试第二部分(转发)

    2010-07-14 17:06:20

    转发:http://soft.zdnet.com.cn/software_zone/2007/0901/482327.shtml


    关于本系列

    跨越边界 系列中,作者 Bruce Tate 提出了这样一个观点:如今的 Java 程序员可以通过学习其他方法和语言得到很好的其他思路。自从 Java 明显成为所有开发项目的最佳选择以来编程前景已经改变。其他的框架正影响构建 Java 框架的方式,从其他语言学到的概念可以影响您的 Java 编程。您编写的 Python(或 Ruby、Smalltalk ... )代码可以改变您处理 Java 编码的方式。

    本系列为您介绍与 Java 开发根本不同,但也可以直接应用于 Java 开发的编程概念和技术。在一些例子中,需要对技术进行集成以利用它。在另外一些例子中,您将能够直接应用这些概念。单独的工具不及其他语言和框架能够影响 Java 社区中的开发人员、框架甚至基本方法的思想那么重要。

    在这由两部分组成的迷你系列的 第 1 部分 中,了解了如何用动态语言促进单 元测试。本文将展示集成环境在功能测 试和集成测试中的优势。单 元测试包括对小的代码片断(例如方法)的测 试,而且经常要把它们与周围的元素隔离开。功能测 试和集成测试测 试的应用程序部分越来越多。功能测 试用于测试单一特性(通常涉及一个接口)、执行任务的业务代码,以及与中间件服务交互的代码(例如数据库)。集成测 试用于测试应用程序的多个不同特性。(功能测 试在不太严谨的情况下通常也被称为集成测 试。)

    Java 开发人员在解决单 元测试问题上已经获得了令人注目的成果,但在集成测 试上则没有带来太多令人兴奋的消息。多数 Java 测 试框架(如 JUnit 或 TestNG)主要侧重于单 元测试。Java 编程中缺乏集成测 试框架的一个原因是缺乏集中的架构或开发哲学。在后面的小节中,我将继续使用 Ruby on Rails 示例,这次的重点放在功能测 试和新的 Rails 集成测 试框架上。您将看到,在使用集成测 试框架时,进行测 试要容易得多。

    运行测试

    如果还没有阅读 第 1 部分,那么请先阅读它。然后,如果想跟随这篇文章一起编写代码,那么请确保您已经获得 一个可工作的 Rails 应用程序。在第 1 部分中,实现了一个简单的单 元测试和几个 fixture。如果您跟随第 1 部分一起编写了代码,但是记不清是否使应用程序处于工作状态,那么您可以利用测 试用例,先切换到项目目录,然后运行 rake 即可。清单 1 显示了我的结果:


    清单 1. 用 rake 运行所有测试
    > bruce-tates-computer:~/rails/trails batate$ rake
    (in /Users/batate/rails/trails)
    /usr/local/ror/bin/ruby -Ilib:test
    "/usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader.rb"
    "test/functional/trails_controller_test.rb"
    Loaded suite /usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader
    Started
    EEEEEEEEEEEEEEEE
    Finished in 0.070797 seconds.

    1) Error:
    test_create(TrailsControllerTest):
    Errno::ENOENT: No such file or directory - /tmp/mysql.sock
    /usr/local/ror/lib/ruby/gems/1.8/gems/activerecord-1.14.0/
    lib/active_record/vendor/mysql.rb:104:in 'initialize'
    /usr/local/ror/lib/ruby/gems/1.8/gems/activerecord-1.14.0/
    lib/active_record/vendor/mysql.rb:104:in 'real_connect'
    /usr/local/ror/lib/ruby/gems/1.8/gems/activerecord-1.14.0/
    lib/ active_record/connection_adapters/mysql_adapter.rb:331:in 'connect'


    ...results deleted...


    8 tests, 0 assertions, 0 failures, 16 errors
    /usr/local/ror/bin/ruby -Ilib:test "/usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/
    lib/rake/rake_test_loader.rb"
    rake aborted!
    Test failures

    (See full trace by running task with --trace)

    可以看到有一些问题存在:rake 生成了 16 个错误。跟踪显示,Rails 无法建立连接。我忘记启动数据库引擎了。我将启动数据库引擎,然后再次运行 rake。这次我得到了清单 2 所示的结果:


    清单 2. 在 rake 内通过测试
    rake 
    (in /Users/batate/rails/trails)
    /usr/local/ror/bin/ruby -Ilib:test
    "/usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader.rb"
    "test/unit/trail_test.rb"
    Loaded suite /usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader
    Started
    ...
    Finished in 0.09541 seconds.

    3 tests, 5 assertions, 0 failures, 0 errors
    /usr/local/ror/bin/ruby -Ilib:test
    "/usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader.rb"
    "test/functional/trails_controller_test.rb"
    Loaded suite /usr/local/ror/lib/ruby/gems/1.8/gems/rake-0.7.0/lib/rake/rake_test_loader
    Started
    ........
    Finished in 0.169756 seconds.

    8 tests, 28 assertions, 0 failures, 0 errors

    这样就好多了。测 试正常运行,而我们准备构建更多测 试用例。如果仔细查看清单 2 就会发现,rake 生成了两组结果。第一组(第 1 部分的单 元测试)看起来应当熟悉。下一组是从框架中自动生成的功能测 试


    控制器和视图快速入门

    在查看测试代码之前,需要对 Rails 的用户界面层有更好的理解。在第 1 部分中,用 script/generate scaffold Trail Trails 生成框架代码时,Rails 根据数据库的内容为应用程序创建了一个控制器和系列视图。控制器的代码位于 app/controller/trails_controller.rb,视图则全部位于 app/views/trails 下的不同目录中。这个应用程序包含:

    • 默认 Web 页面实现,显示路线(trail)列表(叫做 list
    • 路线的细节信息的显示页面
    • 路线的通用表单
    • 创建或编辑路线的页面

    要了解这些是如何组合在一起的,请参见 trails_controller.rb 中的 list 方法,如清单 3 所示:


    清单 3. app/controllers/trails_controller.rb 中的部分代码清单
    def list
    @trail_pages, @trails = paginate :trails, :per_page => 10
    end

    传入的超文传输协议(HTTP)请求进入控制器。(HTTP 是支持浏览器、Rails 和所有基于浏览器的应用程序的底层协议)。在这篇文章后面,您将看到功能测 试如何通过使用 HTTP 命令来调用功能测 试用例。清单 3 的代码设置了 Rails 显示线路的分页列表时需要的实例变量。视图需要一个分页器对象,即 Rails 分配给 @trail_pages 的分页器对象,还需要 @trails 中的路线列表。默认情况下,Rails 使用与控制器方法相同的名称呈现视图。要查看视图,请参阅 app/views/trails/list.rhtml 中的表格定义,如清单 4 所示:


    清单 4. list.rhtml 的部分代码清单
    <table>
    <tr>
    <% for column in Trail.content_columns %>
    <th><%= column.human_name %></th>
    <% end %>
    </tr>

    <% for trail in @trails %>
    <tr>
    <% for column in Trail.content_columns %>
    <td><%=h trail.send(column.name) %></td>
    <% end %>
    <td><%= link_to 'Show', :action => 'show', :id => trail %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => trail %></td>
    <td><%= link_to 'Destroy', { :action => 'destroy', :id => trail },
    :confirm => 'Are you sure?', :post => true %></td>
    </tr>
    <% end %>
    </table>

    Rails 中的视图策略是:创建一个简单字符串,然后做一些替换。这个策略叫做建模,它构成了大多数现代 Web 框架的基础,包括 Java 框架(例如 Tapestry、JavaServer Faces(JSF)、JavaServer Pages (JSP) 和 WebWork)。在这个示例中,Rails 做了以下工作:

    1. 执行 <%%> 之间的代码段(被称为语句),并用代码 段的执行输出替代这一部分。语句可能不存在。

    2. 执行 <%=%> 之间的代码段(被称为表达式), 并用代码段返回的值替代这一部分。

    3. 处理布局、偏好、帮助程序以及其他类型的代码片断时。这些特性允许使用不同的复合部件构建复杂的 Web 页面。在这里,我就不对细节做过多介绍了。

    在有了模板策略之后,现在再来看一下 清单 4。您可以看到访问活动记录 Trail 模型并用 <% for trail in @trails %> 命令在 @trails 中的每条路线上循环的 list.rhtml 视图。(您已经填充了控制器中的 @trails 实例变量)。对于每条路线,该视图都将得到 Trail.content_columns, 它是 trails_development 数据库中 trails 表的列的列表。然后,该视图通过在列表中的每个列上进行循环,提供数据库中每一列的值。trail.send(column_name) 命令把 namedifficultydescription 方法发送给 trail

    现在是在屏幕上查看结果的时候了。如果回忆一下,应当记得您已经在第 1 部分的示例中键入了一些 fixture 形式的测 试数据。要把它们加载到开发环境(fixture 默认装入测 试环境)中,则只需键入 rake load_fixtures 即可。启动 Rails 服务器(在 Unix 上用 script/server,在 Windows 上用 ruby script/server), 把浏览器指向 localhost:3000/trails/list 就可以看到结果。在这个 URL 中,trails 是控制器的名称,list 是动作的名称,由 list 控制器方法实现。图 1 显示了结果:


    清单 1. 列出路线

    正如所期望的那样,可以看到一个包含每条路线的名称、说明和难度的表。接下来,我将介绍 Rails 的功能测 试框架如何只通过一条 HTTP put 命令访问 Web 页面。



    分解功能测试

    回忆一下就可以知道,Rails 单 元测试只处理模型。Rails 中的功能测 试调用 Web 页面,然后检查结果,从上到下地测 试某一特性(包括模型、视图和管制器)。这种级别的集成测 试很重要,因为可以确保系统的主要元素之间的交互与您对所提供的每个特性的预期一样。

    Rails 的每个功能测 试用例都要进行 HTTP putget。它们调用控制器的动作;控制器访问模型和 视图,并呈现 Web 页面和结果。要获得详细的工作示例,请参见 Rails 在框架中生成的测 试用例:


    清单 5. 来自 test/functional/trails_controller_test.rb 的 test_list
    def test_list
    get :list

    assert_response :success
    assert_template 'list'

    assert_not_nil assigns(:trails)
    end

    清单 5 中的测 试用例利用 get :list 命令执行了一个简单的 HTTP get。然后,测 试用例运行了三个断言:

    • assert_response :success:HTTP 命令成功完成。
    • assert_template 'list':控制器动作呈现 list 模板。
    • assert_not_nil assigns(:trails):控制器把 @trails 实例变量分配给一些非 null 的值。

    使用单元测 试框架,如果断言为 ture,没有错误出现,那么测 试用例就通过;否则,测 试用例失败。

    test_list 测 试用例可以声明 :success 响应,但是它应当声明 :redirect (代表 HTTP 重定向)、:missing (代表 not_found),或代表单个 HTTP 返回代码的整数。请参阅 参考资料,获得 HTTP 返回代码的详尽列表。现在请看 test_create, 它使用了一个 HTTP put。请将 test_create 更改成如清单 6 所示:


    清单 6. 测试表单
    def test_create
    num_trails = Trail.count

    post :create, :trail => {:name => "Hermosa Creek", :description =>
    "Lots of altitude, all down", :difficulty => "Medium"}

    assert_response :redirect
    assert_redirected_to :action => 'list'

    assert_equal num_trails + 1, Trail.count
    end

    trails_controller_test.rb 中自动生成的这个测 试用例的版本包括 post :create, :trail => {},它调用 create 方法,空哈希表表示新路线。这个代码应当创建一条新路线,该路线有一个所有属性都为 null 的 Trail 对象。清单 6 修改了代码,以传递代表路线属性的哈希映射表。这个哈希映射表接口对于在测 试框架中指定对象而言非常有用。然后,测 试用例用 Trail 模型确保创建了新路线。

    清单 5 和清单 6 中的测 试用例不像第 1 部分中的单 元测试那样处理每个细节。但是它们可以保证调用了业务逻辑,保证控制器逻辑没有检测到任何错误,并保证得到了正确的 HTTP 响应。

    Rails 还提供了另一种测 试用例:集成测 试


    集成测试

    功能测试用于测 试单一特性,而集成测 试可能触及许多不同的页面。例如,购物车单 元测试可以测 试出您可能通过模型 API 将一件商品添加到购物车中。购物车的功能测 试可以确保您能够通过登录某一 Web 页面将商品添加到购物车中。而集成测 试则可以保证能够登录、添加商品和结账。

    在 “Running Your Rails App Headless”(请参阅 参考资料)中,Mike Clark(Rails 社区领先的测 试专家之一)详细介绍了集成测 试框架。开始进行讨论时,他介绍了如何运行没有 Web 页面的(即 headless)应用程序。这项功能使得搜集编写集成测 试的足够信息变得更容易。从 Rails 1.1 开始,可以直接从控制台调用控制器。不需要浏览器,只要调用 app 对象的 putget 方法,就可以访问应用程序的 Web 页面。

    请启动控制台,键入清单 7 中的命令,通过 HTTP get 发出列表动作:


    清单 7. 从控制台使用 Rails 集成测试框架
    > script/console Loading development environment.
    >> app.class
    => ActionController::Integration::Session
    >> app.get('trails', 'list')
    => 200
    >> app.get("trails/list")
    => 200
    >> app.response =~ /Barton Creek/
    => false
    >> app.response =~ /Emma Long/
    => false
    >> app.response.body =~ /Emma Long/
    => 331
    >>

    在清单 7 中,从控制台以两种形式发送请求,调用 trails 控制器的 list 动作。然后,通过与正则表达式 /Emma Long/ 匹配,可以看到生成的 HTML 页面中包含 Emma Long(一条路线)。您可以继续运行 postget


    清单 8. 通过 post 实现删除
    >> app.post("trails/destroy/1")
    => 302
    >> Trail.find_all
    => [#<Trail:0x25a8e34 @attributes={"name"=>"Bear Creek", "id"=>"2",
    "description"=>"Too many downed trees.", "difficulty"=>"easy"}>]
    >> Trail.find_all.size
    => 1
    >> app.response.redirect_url
    => "http://www.example.com/trails/list"
    >>

    通过控制台集成测 试 API,现在有了构建集成测 试的足够信息。请使用 script/generate integration_test DestroyAndShow 生成一个集成测试,并将它编辑成清单 9 那样:


    清单 9. test/integration/destroy_and_show.rb
    require "#/../test_helper"

    class DestroyAndShowTest < ActionController::IntegrationTest
    fixtures :trails

    def test_multiple_actions
    get "trails/list"
    assert_response :success

    post "trails/destroy/1"
    assert_response :redirect
    assert_nil(response.body =~ /Emma Long/)
    assert_equal(2, Trail.find_all.size)

    follow_redirect!
    assert_response :success


    get "trails/show/2"
    assert_response :success


    end
    end

    这个示例使用的集成框架与前面通过 Rails 控制台使用的框架相同,使用的断言模型也与功能测 试单元测 试框架的模型相同。可以用 rake 运行测 试用例,也可以单独运行每个测 试用例。通过以一致的方式使用控制台和集成框架,可以尝试应用程序的各个方面,获得控制台中的结果,并用这些结果在自动测 试用例中提供您的断言。


    在 Ruby 中测试与在 Java 语言中测试的对比

    现在可以开始查看集成框架中的集成测 试有什么不同了。对于这个示例,可以使用 fixture,它们在集成测 试框架中工作。断言和表示想法的方式(例如请求和响应)都有统一的形式。

    基本 Ruby 语言中的某些功能让 Rails 的测 试更强大。可以使用 Ruby 做类似 mock 和存根所做的事。在编写这篇文章时,我正在使用 Rails 进行一些自动集成测 试。我有一个依赖于当前日期的类。我只是打开了用于 Date 的现有 Ruby 类,并重新定义了 today 方法,让它返回 Date.civil(2, 2, 2006),如清单 10 所示:


    清单 10. 用 Rails 创建存根
    require "#/../test_helper"

    class Date
    def self.today
    return Date.civil(2006, 2, 2)
    end
    end

    class NameOfTest ...continue test case here...

    对于我的测试用例,我什么都不需要做。现在,不论测 试用例什么时候运行,today 都会是美国的假日土拔鼠日。只使用了五行代码,我就有了一个可工作的存根。在这个示例中,这个 mock 对象只能用于测 试用例。如果需要将这个 mock 对象用于多个测 试用例,那么可以给这个 mock 对象添加测 试和模拟的代码,并重新使用它。

    总之,我对 Ruby 的测 试体验的评价是:非常必要(因为动态语言容易出错的特性),并且更强大。其中部分力量来自通过 Rails 使得代码生成、断言、数据库支持,以及诊断工具无缝地在一起工作的集成体验。

    但是 Java 技术确实有自己的优势。在将测 试集成到开发环境方面它做得更好,它还有更好的持续集成工具。也可以找到模拟最常见企业特性的更多框架。Java 开发人员有另一个理论优势:他们可以在没有数据库支持的情况下,更容易地运行应用程序。没有数据库支持就测 试 Rails 应用程序几乎没有意义,因为许多 Rails 值是通过元编程(metaprogramming)把 SQL 特性编织起来而得到的。所以,Java 测 试套件通常运行得更快,因为套件中的测 试用例不需要访问数据库。

    如果使用 Java 代码生成,Rails 可以为您提供一些关于如何使用测 试生成增强您的代码生成的好主意。如果正在补充自己的测 试框架,那么 Rails 的测 试 API 既简单又漂亮。如果对超越 Java 编程语言感兴趣,那么 Rails 可以为轻量级的、数据库支持的应用程序提供一些真正的价值。

    在这个系列的下一篇文章中,我将不再介绍 Rails,而是查看基于 Web 的建模策略。您将看到如何将代码生成用于动态语言。

  • 在 Ruby on Rails 中进行单元测试第一部分(转发)

    2010-07-14 15:00:29

    转发,原地址:http://soft.zdnet.com.cn/software_zone/2007/0901/482329.shtml


    在这一篇和下一篇文章中,将全面理解在 Ruby on Rails 集成开发框架中的测 试方式。第 1 部分侧重于测 试模型对象,并提供一些从 Rails 获得启发的策略,可以用这些策略使 Java 单 元测试更有效。第 2 部分把更多时间花在功能测 试和集成测试上。作为 Java 程序员,您对一些概念可能比较熟悉,特别是在测 试的时候,而其他一些概念可以拓展您的理解。


    补漏

    在这个系列的 前一期 中,了解了动态类型化会带来某些 bug 种类,静态类型化语言将在编译时捕捉到这些 bug。清单 1 的 Ruby 代码片段包含四个不同的 bug,这四个 bug 在运行时之前都不会显露出来:


    清单 1. 带 bug 的 Ruby 代码
     
    position = "2" #string, where a number was intended
    position = positoin + 4 #position is misspelled, evaluates to 0
    puts "The position is:" +
    position.to_string #The method should be to_s

    如果编译器能够捕捉 bug,那么这类 bug 解决起来是小菜一碟,但是如果依赖解释器,那么管理这些 bug 就困难得多。为了处理这些微妙的错误,动态语言的用户长期以来一直依赖于自动测 试。在进行测试的时候,比起其他语言,动态语言及其集成环境在一般意义和特殊意义上都具有显著的优势:

    • 语言更简洁。测 试基本上是脚本编程,许多最好的脚本语言都是动态类型化的。

    • 集成环境支持的假设可以让集成测 试更容易,也可能更强大。在 Rails 环境中将看到一些示例。

    • 动态语言允许使用更松散的耦合,使一些测 试格式更容易实现。

    在了解动态语言开发人员为什么这么热衷于测 试之后,现在是构建一个需要一些真正测 试的实际应用程序的时候了。


    构建一个快速 Rails 应用程序

    为了进展得快些,我采用了一个保存山地摩托车路线数据库的 Rails 应用程序。我将模型的几个测 试放在一起。如果想和我一起编写代码,那么所有需要的工具就是一个数据库引擎(我使用的是 MySQL)和 Ruby on Rails 1.1 或更新版本(请参阅 参考资料)。第一步是创建 Rails 项目。在命令提示符下输入 rails trails 命令,清单 2 显示了命令和结果:


    清单 2. 构建 Rails 应用程序
     
    > rails trails
    create
    create app/controllers
    create app/helpers
    create app/models
    create app/views/layouts

    ...partial results deleted...

    create test/fixtures
    create test/functional
    create test/integration
    create test/mocks/development
    create test/mocks/test
    create test/unit
    create test/test_helper.rb

    ...partial results deleted...

    create config/environment.rb
    create config/environments/production.rb
    create config/environments/development.rb
    create config/environments/test.rb

    ...partial results deleted...

    create log/server.log
    create log/production.log
    create log/development.log
    create log/test.log


    Rails 除了生成空项目什么都没做,但是可以看到它正在为您工作。清单 2 创建的目录中包含:

    因为 Rails 是一个集成环境,所以它可以假设组织测 试框架的最佳方式。Rails 也能生成默认测 试用例,后面将会看到。

    现在要通过迁移创建数据库表,然后用数据库表创建新数据库。请键入 cd trails 进入 trails 目录。然后生成一个模型和迁移(migration),如清单 3 所示:


    清单 3. 生成一个模型和迁移
     
    > script/generate model Trail
    exists app/models/
    exists test/unit/
    exists test/fixtures/
    create app/models/trail.rb
    create test/unit/trail_test.rb
    create test/fixtures/trails.yml
    create db/migrate
    create db/migrate/001_create_trails.rb

    注意,如果使用 Windows,就必须在命令前加上 Ruby,这样命令就变成了 ruby script/generate model Trail

    如清单 3 所示,Rails 环境不仅创建了模型,还创建了迁移、测 试用例和测试 fixture。稍后将看到 fixture 和测 试的更多内容。迁移让 Rails 开发人员可以在整个开发过程中处理数据库表中不可避免的更改(请参阅 跨越边界:研究活动记录)。请编辑您的迁移(在 001_create_trails.rb 中),以添加需要的列,如清单 4 所示:


    清单 4. 添加列
     
    class CreateTrails < ActiveRecord::Migration
    def self.up
    create_table :trails do |t|
    t.column :name, :string
    t.column :description, :text
    t.column :difficulty, :string
    end
    end

    def self.down
    drop_table :trails
    end
    end

    您需要创建和配置两个数据库:trails_testtrails_development。 如果想把这个代码投入生产,那么还需要创建第三个数据库 trails_production,但是现在可以跳过这一步。请用 数据库管理器创建数据库。我使用的是 MySQL:


    清单 5. 创建开发和测试数据库
    mysql> create database trails_development;
    Query OK, 1 row affected (0.00 sec)

    mysql> create database trails_test;
    Query OK, 1 row affected (0.00 sec)

    然后编辑 config/database.yml 中的配置,以反映数据库的优先选择。我的配置看起来像这样:


    清单 6. 将数据库适配器添加到配置中
    development:
    adapter: mysql
    database: trails_development
    username: root
    password:
    host: localhost


    test:
    adapter: mysql
    database: trails_test
    username: root
    password:
    host: localhost

    现在可以运行迁移,然后把应用程序剩下的部分搭建(scaffold)在一起:


    清单 7. 迁移和搭建
    > rake migrate

    ...results deleted...

    > script/generate scaffold Trail Trails
    ...results deleted...

    create app/views/trails

    ...results deleted...

    create app/views/trails/_form.rhtml
    create app/views/trails/list.rhtml
    create app/views/trails/show.rhtml
    create app/views/trails/new.rhtml
    create app/views/trails/edit.rhtml
    create app/controllers/trails_controller.rb

    create test/functional/trails_controller_test.rb

    ...results deleted...


    再次注意,Rails 已经为您创建了测 试用例。框架不仅为这个简单的小程序生成了视图和控制器,而且还生成了有助于测 试用户界面的功能性测 试


    对 Rails 应用程序进行单元测试

    现在是运行一些测 试的时候了。请看第一个测 试,它已经在 test/unit/trail_test.rb 中写好了:


    清单 8. 第一个测试
    require File.dirname(__FILE__) + '/../test_helper'

    class TrailTest < Test::Unit::TestCase
    fixtures :trails

    # Replace this with your real tests.
    def test_truth
    assert true
    end
    end


    确实,这个测试用例算不了什么,但您可以从中看出如何构架测 试代码,而且自己的测 试用例的模板也已经就位。请运行测 试,如清单 9 所示(包括结果):


    清单 9. 运行第一个测试
    > ruby test/unit/trail_test.rb 
    Loaded suite test/unit/trail_test
    Started
    EE
    Finished in 0.027314 seconds.

    1) Error:
    test_truth(TrailTest):
    ActiveRecord::StatementInvalid: Mysql::Error: #42S02Table
    'trails_test.trails' doesn't exist: DELETE FROM trails

    ...results deleted...


    测试用例失败,但是请看输出。第一行执行测 试。第三行 EE 显示测 试的结果。如果测 试用例通过,会得到 “.” 字符。如果测 试用例产生错误,会看到 E。如果某个断言不是 true,那么将看到 F。接下来,可以 看到所请求的全部测试都将完成,以及完成这些测 试需要的时间。最后,将看到每个失败的详细原因。在这个示例中没有表,这是有一定原因的,因为在测 试数据库中还没有创建任何表。通过将开发方案复制到测 试环境,再重新运行测 试,可以修复错误,如清单 10 所示:


    清单 10. 复制方案,重新运行测试
    > rake clone_schema_to_test          (in /Users/batate/rails/trails)
    > ruby test/unit/trail_test.rb
    Loaded suite test/unit/trail_test
    Started
    .
    Finished in 0.038578 seconds.

    1 tests, 1 assertions, 0 failures, 0 errors

    这样更好。但是测 试还是太简单,所以是构建一个真正的测 试用例的时候了。请添加下面这个新测 试用例 test_truth,如清单 11 所示:


    清 单 11. 添加测试用例
        def test_truth
    assert true
    end

    def test_new
    trails = Trail.find_all
    Trail.new do |trail|
    trail.name = "Barton Creek"
    trail.description = "A little water in the Spring. You'll get wet."
    trail.difficulty = "medium"
    trail.save
    end
    bc = Trail.find_by_name("Barton Creek")
    assert_equal "medium", bc.difficulty
    assert_equal trails.size + 1, Trail.find_all.size

    end

    这个代码惊人的紧凑。只需要键入上述代码以及两个断言,就可以操纵持久模型。这种经济的投入正是脚本语言在其他环境中如此流行的原因。测 试也是需要经济投入的地方。

    现在可以运行测试用例,您将看到两个新断言显示在测 试报告中。使用 Ruby 时,只需保存并编译测 试即可。清单 12 显示了测 试运行的结果:


    清单 12. 测试结果
    > ruby test/unit/trail_test.rb 
    Loaded suite test/unit/trail_test
    Started
    .
    Finished in 0.038578 seconds.

    1 tests, 1 assertions, 0 failures, 0 errors
    bruce-tates-computer:~/rails/trails batate$ ruby test/unit/trail_test.rb
    Loaded suite test/unit/trail_test
    Started
    ..
    Finished in 0.182043 seconds.

    2 tests, 3 assertions, 0 failures, 0 errors

    Fixture 和回滚

    Java mock 对象

    在解决测试数据库支持代码的困扰时,Java 开发人员经常使用 mock 对象而不是实际的数据库代码。Mock 对象设置起来比较难,通常难于理解,而且对于在数据库环境中工作的代码,也无法提供良好的理解。Ruby on Rails 支持不同的方式。

    有三个问题影响了对数据库支持代码的测 试。它们都与两个特性有关:性能和重复性。与内存中的操作相比较,数据库调用的性能是非常低的。如果测 试运行需要太长时间,那么您可能就不想运行它们了。另一个问题是一个测 试用例对另一个测 试用例的影响。因为数据库调用在性质上是持续的,所以要把一个测 试在数据库中的变化与另一个数据库中的隔离开。最后的问题是前两个问题的组合。为了让数据库测 试用例可重复而增加设置和拆卸的负担时(为每个新的测 试用例添加记录、运行测 试并删除这些记录),带来的开销可能是让人无法接受的。与这种开销相比,测 试用例开销简直是小巫见大巫。

    Ruby on Railsfixture 和事务回滚来帮助解决这些问题。在 Rails 中,一个 fixture 就是一个包含测 试用例数据的文件。在创建这个简单应用程序时,同时还创建了一个开发数据库和一个测 试数据库。创建开发数据库是很正常的;但是您可能不想让生产代码和开发环境共享同一个数据库。而创建测 试数据库因为另一个原因也很重要。每个测 试都在测试用例开始时装入 fixture 中的测 试数据。然后,测 试用例对数据库进行修改,并测 试这些修改的结果。最后,Rails 回滚这些变化,将数据库返回到测 试方法运行之前的状态。

    现在要制作一个测 试 fixture 并为它编写一个测 试。请编辑 test/fixtures/trails.yml 文件,添加一个记录,如清单 13 所示:


    清单 13. 添加记录
        first:
    id: 1
    name: "Emma Long"
    description: "A real bike breaker."
    difficulty: "hard"
    another:
    id: 2
    name: "Bear Creek"
    description: "Too many downed trees."
    difficulty: "easy"

    清单 13 使用叫做 YAML 的语言,这个语言描述结构化的数据(请参阅 参考资料)。此文件对空格很敏感,所以该当用空格代替制表符并完全按原样键入数据项时,请确保 删除了所有尾部空格。

    同样,还要把这个测 试用例添加到 trails_test.rb 中:

        def test_find
    assert_equal "Emma Long", Trail.find(1).name
    assert_equal "easy", Trail.find(2).difficulty
    end

    同样,可以用 5 个 passing 断言运行这些测 试。如果您愿意,还可以按名称引用每个 fixture。例如,要根据名为 first 的 fixture 来创建对象,可以使用 Ruby 代码 trails[:first]。让 fixture 对所有测 试用例或只对需要它们的测 试用例可用,这极大地简化了创建或毁坏数据库数据所需要的代码。


    在 Java 编程中测试

    知道了测试在其他语言中如何发生,就可以改进在 Java 平台上进行测 试的方式。具体地说,使用这些想法中的一项或多项可以对测 试产生显著而直接的影响:

    • 可以把测试用例的生成添加到任何现有代码生成当中。Ruby on Rails 通过在默认情况下创建一些简单的测 试用例来取得了巨大优势,您也可以这么做。

    • 可以用事务-回滚技术让数据支持的测 试运行得更快。Spring 框架有一些现有的拦截器,可以让这项技术易于使用。

    • 实际上可以用动态语言驱动测 试。Jython、Ruby 和 Groovy 是三个实际可能。

    如果觉得愿意采用其他语言进行测 试,那么可以使用某种 JVM 语言,例如 JRuby(请参阅 参考资料)。JRuby 还没有高级到可以运行 Ruby on Rails,但是它是 Java 应用程序卓越的测 试平台。只是作为尝试,JRuby 的开发人员 Charles O'Nutter 提供了以下测 试 EJB 的示例:


    清单 14. 用 JRuby 测试 EJB 组件
        require 'test/unit'
    require 'java'

    include_class "my.pkg.EJBHomeFactory"

    class TestMyBean < Test::Unit::TestCase
    def test_finder
    wh = EJBHomeFactory.widget_home
    w = wh.find_by_color("blue")
    assert_not_nil(w)
    end

    def test_widget
    wh = EJBHomeFactory.widget_home
    w = wh.find_by_name ("superWidget")

    assert_equal("blue", w.color)
    assert_equal(14, w.id)
    end
    end

    可以看到,用 Ruby 编写执行 Java 代码的测 试用例实际上非常容易。在这个示例中,Ruby 代码发现一个 EJB 组件,并为用户返回的 bean 提供了一些断言。测 试用例当然比多数 Java 测 试都容易,使用 Ruby 编写测 试用例是一个获得更高的生产率和速率的一种好方法。我还看到针对 Jython 或 Groovy 的类似策略(请参阅 参考资料)。

    第 2 部分将进一步深入查看 Rails 的测 试,包括运行更高层次测 试(叫做功能测 试和集成测试)的代码。

  • selenium还没解决的问题

    2010-06-08 10:21:21

    1.在一个case中曾遇到一个弹出确认框,没办法录制到,自己写代码也一直不能成功捕获,其实是还没弄清楚那究竟是个什么组件(是只有确认的提示框),可以多看看JavaScript和html

    2.很多步骤在单步执行时可以通过,但case整体执行时却报错,其中最为常见的是“Element……can't be found”。还不知道是什么原因导致的

    3.在页面上有子目录而子目录是光标在目录上(而不点击)时可显示时,容易找不到子目录,还没找到解决方法

    4.关于不同浏览器的应用,或许是因为我电脑上装了IE的三个版本,本身存在问题,再有就是那个自定义浏览器的应用没试验成功(*custom <path to browser>)。找时间去只有一个IE版本的机器上试验一下
  • selenium 小结(一)

    2010-06-07 17:06:33

    最近一直在用seleniumIDE做测试用例,碰到了很多问题,但由于一直混乱,所以一直没时间没心情来总结一下
    现在终于有点感觉了,觉得自己努力就可以做出来了。趁着今天刚刚完成一部分,来总结一下的。

    1、如果打开新页面后输入信息时提醒找不到elements,则可以先用focus命令选中要输入的文本框

    2、打开popup后如何关闭的问题:先用selectPopUp来选中,再用Close命令来关闭,光标就可以回到原本的页面了

    3、若打开新页面后找不到elements,则可能是因为页面没有完全打开,所以找不到,这时把前边的Click改为clickAndWait

    4、如果页面中有通过文本框输入来自动选择下面内容的(例如你输入邮编,则下面的城市、国家自动选择),在输入邮编后,要点击一下页面下面的选项才会填充进来,但click命令需要表明组件位置,此时可用type下面的文本框来等待,但输入的值要为空,而且之后要再重新给该文本框输入正确的值。以下为截取的command
       type     
    PageContainer_InterContainerConsultantRegInfo_ConsultantRegInfo_InterContainerRegCustomerInfoMail_RegCustomerInfoMail_txt_Zip  77040
       type PageContainer_InterContainerConsultantRegInfo_ConsultantRegInfo_InterContainerRegCustomerInfoMail_RegCustomerInfoMail_txt_HomePhone 

       type PageContainer_InterContainerConsultantRegInfo_ConsultantRegInfo_InterContainerRegCustomerInfoMail_RegCustomerInfoMail_txt_HomePhone   1452365478

    5、在录制时,用快捷键进行的操作很可能会录制不上,例如登陆,按Enter则不会录制上本该有的Click命令,要用鼠标点击

    6、在同一页面上要输入两个地址或联系人等之类的时,如果有The same as的选项,选上之后要验证两边是否完全一样,则可以把其中原始的值保存下来(storeValue),再用waitForValue()来验证输入值是否和原始的一样

    暂时想到的就这么多,想到了再继续写的。


  • QTP和LR的区别

    2010-05-13 17:05:36

    QTP: 基于UI对象的功能测试
    LR: 基于协议的性能测试
    QTP 录制原理:消息机制,截获消息。录制的前提是能识别控件。
    LR录制原理:捕获数据包。录制的前提是能识别协议报文。
  • Analysis图

    2010-04-28 13:56:36

    一、Vuser图

    1、正在运行的Vuser图:显示在测试期间的每一秒内,执行Vuser脚本的Vuser的数量及它们的状态。
    2、Vuser概要图:显示Vuser性能的概要,可查看成功的完成场景或会话步骤运行的Vuser的数量。
    3、集合图:表明从集合点释放Vuser的时间,以及在每个点释放的Vuser的数量。有助于理解事务的执行时间。

    二、错误图

    1、错误统计信息图:显示场景或会话步骤执行期间发生的错误数(按错误代码分组)
    2、错误统计信息(按描述)图:显示场景或会话步骤执行期间发生的错误数(按错误描述分组)
    3、每秒错误数图:场景或会话步骤运行期间每一秒内发生的平均错误数
    4、每秒错误数(按描述)图:场景或会话步骤运行期间每一秒内发生的平均错误数(按错误描述分组)

    三、事务图

    1、平均事务响应时间图:每一秒内执行事务所用的平均时间
    2、每秒事务数图:每一秒中,每个事务通过、失败以及停止的次数,此图可帮助确定系统在任何给定时刻的实际事务负载。
    3、每秒事务总数:每一秒中通过的事务总数、失败的事务总数以及停止的事务总数
    4、事务概要图:总结场景或会话步骤中失败。通过、停止以及因错误而结束的事务数目。
    5、事务性能概要图:场景或会话步骤中所有事务的最小、最大和平均性能时间。
    6、事务响应时间(负载下)图:正在运行的Vuser图和平均事务响应图的组合,它指示事务时间,该事务时间与场景或会话步骤中在任一给定时刻所运行的Vuser数目有关。此图可帮助查看Vuser负载对性能时间的总体影响,对分析具有渐变负载的场景或会话更为有用。
    7、事务响应时间(百分比)图:分析在给定时间范围内执行的事务的百分比。此图可帮助确定合适的事务的百分比,以符合系统的性能标准。
    8、事务响应时间(分布)图:执行事务所用时间的分布。如果将它与事务性能概要图进行比较,则可以了解平均性能的计算方法。

    四、Web资源图

    1、每秒点击次数图:Vuser每秒向Web服务器提交的HTTP请求数。借助此图可依据点击次数来评估Vuser产生的负载量。可将此图与平均事务响应时间图进行比较,以查看点击次数对事务性能产生的影响。
    2、吞吐量图:每一秒内服务器上的吞吐量。度量单位是字节,表示Vuser在任何给定的某一秒上从服务器获得的数量。借助此图可依据服务器吞吐量来评估Vuser产生的负载量。可将此图与平均事务响应时间图进行比较,以查看吞吐量对事务性能产生的影响。
    3、HTTP状态代码概要图:从Web服务器返回的HTTP状态代码数,该图按照状态代码分组。
    4、每秒HTTP响应数图:每一秒内从Web服务器返回的HTTP状态代码数,该图按照状态代码分组。
    5、每秒下载页面数图:每秒内从服务器下载的网页数。使用此图可依据下载的页数来计算Vuser生成的负载量。
    6、每秒重试次数图:
    7、重试次数概要图:服务器尝试的链接次数,它按照重试原因分组。
    8、连接数图:每个时间点上打开的TCP/IP连接数。当一个HTML页上的链接转到其他Web地址时,该页可能导致浏览器打开多个连接。此时每个Web服务器打开两个连接。(不太明白还)
    9、每秒连接数图:每一秒内打开的新的TCP/IP连接数和关闭的连接数。
    10、每秒SSL连接数图:每一秒内打开的新的以及重新使用的SSL连接数。

    五、网页细分图

    1、页面组件细分图:每个网页及其组件的平均下载时间
    2、页面组件细分(随时间变化)图:每一秒内每个网页及其组件的平均响应时间
    3、页面下载时间细分图:每个页面组件的下载时间的细分,可以据此确定在网页下载期间,响应缓慢的原因是网络还是服务器有问题。
    4、页面下载时间细分(随时间变化)图:每一秒内每个页面组件下载时间的细分。使用此图可以确定网络或服务器问题发生在场景或会话步骤执行期间的哪一时间点。
    5、第一次缓冲细分时间图:成功收到从Web服务器返回的第一次缓冲之前的这一段时间内,每个网页组件的相关服务器/网络时间。
    6、第一次缓冲时间细分(随时间变化)图:成功收到从Web服务器返回的第一次缓冲之前的这段时间内,场景或会话步骤运行的每一秒中每个网页组件的服务器时间和网络时间。
    7、已下载组件大小图:每个网页组件的大小。

    六、用户定义的数据点图

    1、数据点(总计)图:在场景或会话步骤运行的整个过程中,用户定义的数据点的值的总和。此图通常指出所有虚拟用户能够生成的度量总数。
    2、数据点(平均)图:在场景或会话步骤运行期间,所记录的用户定义的数据点的平均值。此图通常用于确定度量的实际值。

    七、系统资源图

    1、Windows资源图
    2、UNIX资源图
    3、服务器资源图:显示场景或会话步骤运行期间度量的在远程Unix服务器上使用的资源(CPU、磁盘空间、内存或服务)。它可以帮助确定Vuser负载对各种系统资源的影响。
    4、SNMP资源图:使用简单网络管理协议(SNMP)显示运行SNMP代理的计算机的统计信息。
    5、Antara Flame Thrower资源图:运行期间Antara Flame Thrower服务器上的资源使用情况统计信息。
    6、SiteScope图:运行期间SiteScope计算机上的资源使用情况统计信息。

    八、网络监控器图

    1、网络延迟时间图:显示源计算机与目标计算机(例如,数据库服务器和Vuser负载生成器)之间的整个路径的延迟。该图将延迟映射为场景或会话步骤已用时间的函数。
    2、网络子路径时间图:根据场景或会话已用时间,网络子路径时间图将显示从源计算机到路径上每个节点的延迟。
    3、网络段延迟图:根据场景或会话步骤已用时间来显示路径上每个段的延迟。

    九、防火墙服务器监控器图

    1、检查点防火墙-1服务器图:有关检查点的防火墙服务器的统计信息。

    十、Web服务器资源图

    1、Apache服务器图
    2、Microsoft Information Internet Server(IIS)图
    3、iPlanet/Netscape服务器图
    4、iPlanet(SNMP)服务器图

    十一、Web应用程序服务器资源图

    十二、数据库服务器资源图

    十三、流媒体图

    十四、ERP/CRM服务器资源图

    十五、Java性能图

    十六、应用程序组件图

    1、Microsoft COM+图
    2、.NET细分图:概述了关于.NET类或方法的基本结果数据,并以表格格式表示。使用此图,可以迅速识别测试期间最耗时的.NET类或方法
    3、.NET平均响应时间图:执行.NET类或方法所需的平均时间
    4、.NET调用计数图:测试期间调用.NET类和方法的次数。该图最初显示.NET类,但是也可以通过使用向下搜索或筛选技术查看其类中的单个方法。
    5、.NET资源图:可以监控应用程序、程序集、类和方法级别上的.NET计数器。

    十七、应用程序部署解决方案图

    十八、中间件性能图

    十九、安全图

    二十、应用程序流量管理图

    二十一、基础结构资源图

    1、网络客户端图:显示场景或会话步骤运行期间FTP、POP3、SMTP、IMAP和DNS Vuer的网络客户端数据点。

  • 关于web page breakdown

    2010-04-27 10:07:01

    前两天做LoadRunner实例的时候,发现教程上写得结果上的web page breakdown图我的没数据资源,网上搜了好多,后来还看了帮助文档,按帮助文档上写得把controller中的启用网页诊断选中(Diagnostics->distribution->enable the following diagnostics->web page diagnostics),再次运行,结果还是不行。

    后来在论坛上发了求助帖,终于有高手帮忙解答了,要再把Run-time Settings中的Preferences,把“Page per second”选上,这次再试验,终于成功了

  • 精通与实战1

    2010-04-23 15:19:05

    1、如果在图像检查中遇到了差异或者异常,可以禁用【vuser】->[run-time settings]->browser emulation中的Download non-HTML resources选项,因为每次访问网页时,一些图像会随之改变(例如广告横幅)。

    2、要插入检查点时,一定要记得把【vuser】->[run-time settings]->[preference]中Enable image and text check选中

    3、sql server的协议仅支持sql server 7及以下的版本。sql2000以上版本必须使用odbc或其他的对等协议。。。

    4、LR自带定时程序,在场景开始时间中设定计划开始时间即可,但一定要点开始场景按钮,此时会弹出计划场景开始倒计时的窗口
    如果不点开始场景按钮,定时程序不会启动

    5、如何让多个场景轮流执行:如果是两个不同的测试脚本,甚至两个不同的测试环境,都可以在Controller里面进行设置,按照Group执行。

    Controller里面的Group功能要充分利用,可以进行不同脚本的组合,设置不同的RTS。等等

    设置两个Group。点击Edit Schedule->选择Schedule by Group->设置Start when group XXX finishes

    但我觉得不用分开那么多脚本,把transaction名字用参数替换即可,而参数的更新策略用each iteraction,这样应该就可以区分开了

  • LoadRunner学习小总结+小计划

    2010-04-23 13:01:34

        进公司已经将近四周,没事的时候就是自己学习LoadRunner,能有时间学习这个,还是很开心的。

        一段时间学习下来,感觉还是困难挺多的,关键是没有老师,虽然网上资料是蛮多的,但有时自己的具体情况也没办法讲的很清楚,所以会为一个小问题耗时很久。再就是学的没有计划,就是网上找资料,看资料,或者按照找来的资料做例子,例子做的时候是一步步按书上来的,很容易做完就忘,而且很多是不理解。不知道为什么要这么做,不知道那些结果和脚本是怎么出来的,也不知道脚本是什么意思,只会录制脚本,设置场景,生成结果,但结果都不是很会分析。

        想想为什么会这样,有客观原因,更多的可能就是自己的原因了。总是习惯做东西不求甚解,不去追根问底,脚本生成了就是生成了,也不会去管他什么意思,很多事情为什么要那么做也不去仔细想。这种性格有时会让我过得比较轻松,但很多时候也会阻碍我的学习。

        为了能把LoadRunner学好学精,决定在学习上要有所改进,不能再让这种性格影响工作。

    现在想得学习计划就是:

    1、首先把自带例子做好,把这个实例的每个部分都弄清楚,弄懂。脚本要看,结果要仔细分析,涉及到有关设置时就彻底把那个设置搞清楚。

    2、把《精通软件性能测试与LoadRunner实战》这本书吃透,这样性能测试也有了宏观的了解,LoadRunner的使用也可以上一个台阶。

    3、学习常用的脚本语言,或许需要重新学习C语言,毕竟以后要自己写脚本的时候还是不少的。学习时要多多实践,可以自己写,然后再调试,多练习多实践始终是王道!

     

    大概通过半年的学习来对LoadRunner有个大致的了解,做到能用它来完整的对项目进行性能测试。

    或许公司一时还不能给我用LoadRunner的机会,但不能放下,一定要坚持学下去,这样在需要用得时候就可以拿起来就用了,以后也会有更多的机会。

  • Web Page Breakdown

    2010-04-20 13:33:26

      

    1、概念说明:http://bbs.51testing.com/thread-56564-1-1.html

    DNS解析时间:显示使用最近的DNS服务器将DNS名称解析为IP地址所需的时间;DNS查找度量是指示DNS解析问题或DNS服务器问题的一个很好的指示器;
    Connect时间:显示与包含指定URL的Web服务器建立初始连接所需的时间;Connect度量是一个很好的网络问题指示器;它还可表明服务器是否对请求做出响应
    First buffer时间:显示从初始HTTP请求到成功收回来自WEB服务器的第一次缓冲时为止所经过的时间;First buffer度量是很好的Web服务器延迟和网络滞后指示器
    SSL Handshaking time:显示建立SSL连接所用的时间
    Receive Time:显示从服务器收到最后一个字节并完成下载之前经过的时间;接收度量是很好的网络质量指示器
    FTP验证时间:显示验证客户端所用的时间
    Client Time:显示因浏览器思考时间或其他与客户端有关的延迟而使客户机上的请求发生延迟时,所经过的时间。
    Error时间:显示从发出HTTP请求到返回错误消息这期间所经过的平均时间

    2、Web Page Breakdown(网页元素细分) http://tech.it168.com/d/2008-04-17/200804172126926_2.shtml

    “网页元素细分”主要用来评估页面内容是否影响事务的响应时间,通过它可以深入地分析网站上那些下载很慢的图形或中断的连接等有问题的元素。

        1、Web Page Breakdown(页面分解总图)

        “页面分解”显示某一具体事务在测试过程的响应情况,进而分析相关的事务运行是否正常。

        “页面分解”图可以按下面四种方式进行进一步细分:

        1)、Download Time Breaddown(下载时间细分)

        “下载时间细分”图显示网页中不同元素的下载时间,同时还可按照下载过程把时间进行分解,用不同的颜色来显示DNS解析时间、建立连接时间、第一次缓冲时间等各自所占比例。

        2)、Component Breakdown(Over Time)(组件细分(随时间变化))

        “组件细分”图显示选定网页的页面组件随时间变化的细分图。通过该图可以很容易的看出哪些元素在测试过程中下载时间不稳定。该图特别适用于需要在客户端下载控件较多的页面,通过分析控件的响应时间,很容易就能发现那些控件不稳定或者比较耗时。

        3)、Download Time Breakdown(Over Time)(下载时间细分(随时间变化))

        “下载时间细分(随时间变化)” 图显示选定网页的页面元素下载时间细分(随时间变化)情况,它非常清晰地显示了页面各个元素在压力测试过程中的下载情况。

        “下载时间细分”图显示的是整个测试过程页面元素响应的时间统计分析结果,“下载时间细分(随时间变化)”显示的事场景运行过程中每一秒内页面元素响应时间的统计结果,两者分别从宏观和微观角度来分析页面元素的下载时间。

        4)、Time to First Buffer Breakdown(Over Time)(第一次缓冲时间细分(随时间变化))

        “第一次缓冲时间细分(随时间变化)”图显示成功收到从Web服务器返回的第一次缓冲之前的这段时间,场景或会话步骤运行的每一秒中每个网页组件的服务器时间和网络时间(以秒为单位)。可以使用该图确定场景或会话步骤运行期间服务器或网络出现问题的时间。

        First Buffer Time:是指客户端与服务器端建立连接后,从服务器发送第一个数据包开始计时,数据经过网络传送到客户端,到浏览器接收到第一个缓冲所用的时间。

        2、Page Component Breakdown(页面组件细分)

        “页面组件细分”图显示每个网页及其组件的平均下载时间(以秒为单位)。可以根据下载组件所用的平均秒数对图列进行排序,通过它有助于隔离有问题的组件。

        3、Page Component Breakdown(Over Time)(页面组件分解(随时间变化))

        “页面组件分解(随时间变化)”图显示在方案运行期间的每一秒内每个网页及其组件的平均响应时间 (以秒为单位)。

        4、Page Download Time Breakdown(页面下载时间细分)

        “页面下载时间细分”图显示每个页面组件下载时间的细分,可以根据它确定在网页下载期间事务响应时间缓慢是由网络错误引起还是由服务器错误引起。

        “页面下载时间细分”图根据DNS解析时间、连接时间、第一次缓冲时间、SSL握手时间、接收时间、FTP验证时间、客户端时间和错误时间来对每个组件的下载过程进行细分。

        5、Page Download Time Breakdown(Over Time)(页面下载时间细分(随时间变化))

        “页面下载时间细分(随时间变化)”图显示方案运行期间,每一秒内每个页面组件下载时间的细分。使用此图可以确定网络或服务器在方案执行期间哪一时间点发生了问题。

        “页面组件细分(随时间变化)”图和“页面下载时间细分(随时间变化)”图通常结合起来进行分析:首先确定有问题的组件,然后分析它们的下载过程,进而定位原因在哪里。

        6、Time to First Buffer Breakdown(第一次缓冲时间细分)

        “第一次缓冲时间细分”图显示成功收到从Web服务器返回的第一次缓冲之前的这一段时间内的每个页面组件的相关服务器/网路时间。如果组件的下载时间很长,则可以使用此图确定产生的问题与服务器有关还是与网络有关。

        网络时间:定义为第一个HTTP请求那一刻开始,直到确认为止所经过的平均时间。

        服务器时间:定义为从收到初始HTTP请求确认开始,直到成功收到来自Web服务器的一次缓冲为止所经过的平均时间。

        7、Time to First Buffer Breakdown(Over Time)(第一次缓冲时间细分(随时间变化))

        “第一次缓冲时间细分(随时间变化)”图显示成功收到从Web服务器返回的第一个缓冲之前的这段时间内,场景运行的每一秒中每个网页组件的服务器时间和网络时间。可以使用此图确定场景运行期间服务器或网络出现问题的时间点。

        8、Downloader Component Size(KB)(已下载组件大小)

        “已下载组件大小”图显示每个已经下载的网页组建的大小。通过它可以直接看出哪些组件比较大并需要进一步进行优化以提高性能。

  • Error 27492

    2010-04-16 15:34:58

         运行LoadRunner自带实例时开始出现了27727的错误,查到有前辈说可以通过选中run-time setting->internet protocol->preferences中advanced中的Winlet replay instead of Sockets(Windows Only)来解决,尝试之后发现原来的错误没有了,又出现27492的错误,这次查了好久也没找到解决办法,很多人说是connection timeout值设置太小,设大点就OK了,但总感觉不是这个的问题,也有人说时间都设置到最大值了还是报错,所以我没有改时间设置。

        后来实在没办法,就想重新运行一下看看的,结果竟然全部通过了……

        还是没弄明白是什么问题,以后找到了再来添加。

  • Error 27727-27728解决方法

    2010-04-16 14:33:35

    Loadruner报错:Error -27728: Step download timeout (120 seconds)的一个解
    今天一个网友问了我一个问题如下:
    loadruner报错:Error -27728: Step download timeout (120 seconds) 如何解决
    语法检查通过,但是在并发执行一个查询时候报错Action.c(16): Error -27728: Step download timeout (120 seconds) has expired when downloading non-resource(s),请问有啥子解决方法,我使用web_set_timeout ,好象不起作用,直接在option中设置timeout时间为600,(单位应该是秒吧)还是没有起作用,结果都还是提示(120seconds),说明还是以120秒来判断的;使用lrs_set_recv_timeout,语法检查不过,说明库函数里面没有这个函数,

    尝试步骤:
    设置超时时间到600秒,回放还是出错。

    后来设置了runt time setting中的internet protocol-preferences中的advaced区域有一个winlnet replay instead of sockets选项,选项后再回放就成功了。

    kernzhang解释如下
    这个问题很有意思!呵呵!首先LR是通过Microsoft WinInet DLL去录制web协议的!但是在Control运行的时候它默认通过socket去模拟请求,因为这些可以真实的模拟带宽,而采用Microsoft WinInet DLL通过这个DLL去访问网卡方式去模拟带宽,使得模拟不是很精确!而且也不支持unix的应用,但是使用这个确实有时无法处理winnet Dll的一些请求,我认为是它的一些BUG,比如说:回放时它会检查Content-Length,但是网页支持receive more data时,这时socket模拟会一直等待直到timeout!

    先说了一些优缺点,最后回到这个问题!这个问题分两个方面分析:
    第一:你要明白web_set_timeout()这个函数的适用范围!比如说一个web_submit_data()中实际涵盖了10个对Server 端的请求,这个函数是针对10个请求的总和时间的!(别犯低级错误,timeout分了connect,receive以及download三个部分:) )
    第二:就是我解释的上面的一些BUG问题!
    WinInet dll在新版本中处理请求时可以异步的,就是不再是那种连接等待然后超时模式!但是LR用的socket是同步请求!只有等到timeout才会退出!microsoft已经明确表示INTERNET_OPTION_RECEIVE_TIMEOUT 不再适用于 Microsoft Internet Explorer 5.0,显而易见,他们处理请求采取了异步处理的方式!呵呵!这下大概可以圆满解释你的问题了!呵呵

    这里,我补充如下:
    VuGen专用的基于套接字的重播是一种可伸缩以便进行负载测试的轻型引擎。使用线程时是准确的。基于套接字的引擎不支持socks代理服务器。如果在这样的环境中录制,应该使用winInet重播引擎。

    欢迎大家继续讨论。
     
     
     
  • LoadRunner自带实例安装问题(补充)

    2010-04-15 15:17:23

    关于登陆问题还看到另一个解决办法,虽然没有试过,但先写下来,或许以后有用

    声明我的是LR8.0的
    我的解决的办法是:
    1.删除cookies
    2.删除所有历史记录

  • LoadRunner自带实例安装问题

    2010-04-15 13:14:59

        昨天安装了loadrunner的sample,但安装好后发现不能使用,首先是xitami就启动不了,报错为:could not open ftp port21-port is already used by another server,自然网页也就打不开的。因为安装的时候有个地方要写用户名和密码,我就随便自己写了,后来看别人的安装过程是一路next,就担心是这个导致的,所以重新安装了,还是不行

        网上查了查网页报的错:HTTP 错误 404 - 文件或目录未找到。Internet 信息服务,有同志说这是IIS的问题,搞了半天IIS,很多人说是要把IIS中web服务扩展(active server page)允许,就是可以有动态的.asp。但我的Internet 信息服务中根本没有这一项(这个问题现在还没搞清楚……)。后来在请教一个同事的时候,终于想起来可以要把xitami和错误信息一起搜,果然找到了解决办法

    到Xitami的安装路径下,找到Xitami.config并用记事本打开
    找到[Server]下的portbase把它改成
    portbase=1000
    如果你开了IIS服务就改成
    portbase=1001
    但要注意运行IE时
    URL要把Localhost或127.0.0.1
    换成   机器名:1080(对应于portbase=1000):1081(对应于portbase=1001)
    如:http://mengxingshifen:1081/MercuryWebTours/
     
    注意要把机器名也加上,portbase的1000可以改成其他的如8000 则web端口就是8080, ftp端口就是8021
    计算方法是:你改的数据+80=web端口 你改的数据+21=ftp端口
     
    如果还不可以,可以尝试以下操作:
    IE>Tool>internet options>Connection>Lansetting>只勾Automation detect settings.
    如果只出来部分页面:IE>Tool>internet options>Advance>恢复默认。
    实在不行换个浏缆器,如netcape或firefox试试。
    你要仔细看一下Xiatami的属性(右键)。看一看你输入的URL与它的是否相同。
    再不行就关掉Xiatami
    直接上在线的http://newtours.mercuryinteractive.com/tour/
    用户名和密码也是jojo/bean与例子几互一样
     
    之后就ok了,但发现登陆时文档中所给的jojo和bean不能用,自己注册了一个,关掉网页后再次登陆竟然也不能用了,不知道怎么回事。
    刚刚找到答案了:原来是输入用户名和密码后不能用回车,而要点击login按钮(这很不人性,可以算个bug了都)
  • 软件测试人员容易遗漏的测试缺陷(转发)

    2010-04-01 13:25:02

    通常软件测试会暴露软件中的缺陷,经过修正后可以保证软件系统的功能满足需求并正确运行。但是,在系统测试和确认测试中,测试人员容易遗漏一些隐藏的缺陷。众所周知,软件测试不可能发现所有的缺陷,而软件开发周期各个阶段仍然存在注入缺陷的可能,但是,有一些缺陷是测试中容易忽略的,也就是说,通过测试方法和用例可以充分暴露这些缺陷,遗憾的是,它们往往被忽略或者某种原因忘记测试了,这就给软件留下了隐患或者危机。这些容易被忽略的缺陷包括:

    1、安装缺陷

           通常项目组完成代码后,发布时候安装打包是最后一个环节,而软件测试人员通常在测试的时候,没有仔细的测试这一部分,而把用例集中在其他功能上。安装时候的缺陷通常通过拷贝而不是运行安装程序方式给测试人员安装软件,结果正式安装时候出现问题,引起例如控件没有注册,注册表没有导入等。删除时候没有注意安装文件夹是否存在用户文件,造成数据丢失;使用绝对路径;安装顺序没有说明书。

    2、配置文件

           有些文件在ini等配置文件中写出了管理员口令密码等信息,而且是明文的!这是一个安全隐患。另外,有些安装文件的 XML 文件,为了方便在数据库和中间层连接文件中写入了Admin 口令和密码。作为一个合格的软件测试人员,必须检查这些可以用记事本打开的文件。因为,一个稍有常识而且喜欢探索的用户,可能从中获取信息而成为不自觉的黑客。所以,配置文件可能成为软件安全方面的一个缺陷。

    3、网页安全缺陷

           现在网站开发已经注意到:登陆网站进入其内部网页后,直接拷贝网址,然后粘贴到另一IE 窗口输入,可以绕过登陆直接访问。也许商业网站很关注这个问题,但是很多行业软件却很容易忽略。

    网页安全缺陷还可能存在于 IE 弹出的子窗口。有些设计不严格的软件,在主页面关闭的时候子页面还可以运行,这是一个明显的漏洞,而且还大大增加了错误发生的几率。

    4、判断顺序/逻辑缺陷

    对界面进行多个输入判断的时候,非常容易出现这种问题。例如判断年月顺序,判断长度,判断非空等。假如操作员仅仅满足单个条件,保存不能成功;而按界面从上之下顺序一一满足条件之后,保存是没有问题的。但是,改变一下输入的次序,校验失效。例如,一一满足条件之后,不保存,倒过来将上面的输入改成非法输入,然后保存,结果居然也能成功,这是因为原先的判断由于发生过,或者根据语句顺序只检查最后一个判断,所以没有报错。这种错误尤其在 Java scrīpt 脚本的页面中要注意。能够保存不能保证数据正确,有可能引起系统崩溃或者后续数据错误。所以,在测试的时候,不要按照正常的顺序输入,而是要打乱步骤,看看代码是否强健,是否在判断逻辑上没有错误。良好的代码应该经得起折腾,至少保存时会再此全部进行判断,而不只是简简单单走到判断的最后一行。

    5、调试语句和冗余信息

    维护项目和升级改造的推广系统最容易潜伏这类缺陷。典型表现在没有删除或者屏蔽调试语句。弹出一个界面不友好的提示信息,会使不明真相的用户产生误以为系统发生了严重故障,从而引起对软件的不信任感。页面中某个角落存在当前客户不需要的冗余按钮和功能也是一种缺陷。多余的功能会使用户以为是额外附加部分而去使用,其结果可想而知;而多余的按钮会误导好奇心强的用户操作,产生不必要的错误。

    同样值得关注的还有参数设置,由于没有实际数据,开发人员在调试或者单元测试的时候,习惯性的进行自我设定而忘了删除,软件测试人员可能会忽略掉了这部分测试,也可能导致在客户现场发生错误而影响系统发布和验收。

    6、不可重现的故障

    新参加软件测试的人员或者新来的开发人员总是要问,不可重现的缺陷是否需要记录,有必要吗?回答是肯定的。测试必须如实的记录发生的问题,也许不能重现,或者使非软件系统本身问题,但是,可能这些偶然性背后是有规律的,不记录这些,就不可能发现这些规律。

    7、多节点的逆向流转缺陷

    当前软件不少喜欢使用工作流来驱动。工作流的问题,就是可能出现多个流向分支。测试容易忽略的部分,就是工作流多节点的逆向流转。例如,通过不通过涉及两个分支,但是流程逆转的时候,有可能不是回到上一节点而是平级的另一个节点去了。软件测试要格外注意这类用例的设计。另外,有些时候默认分支在向前的时候是有默认值的,例如默认通过,那么保存的时候要提示用户是否通过,否则可能由于操作疲劳而走错了节点,引起回退。

    8、输入框缺陷

    试过往输入框粘贴数据而不是直接输入吗?可能这里会出现问题。按 Ctrl+V 的时候,输入框会根据长度大小自动截断输入长度。但是用鼠标,截断可能会失效。有一次测试人员就是用这种方法把一篇 Word 文档输入进去了,保存的时候,数据库崩溃。有些网站登陆的口令****可以拷贝下来的,只要放在剪贴板里面马上明文显示。

    输入框可以说是问题最多的部分,能够引起的麻烦也很多。日期、数字、文本等等,都需要耐心的测试一下。

    9、界面布局缺陷

    曾经有一次,项目经理回来向测试部反映一个问题,客户对界面不满意。原因很简单,因为界面上删除按钮和保存按钮挨得很近。结果有些操作不熟练的业务人员,很容易误按。这个问题是测试人员没有意料到的,因此注意关闭、删除、退出按钮与保存、下一步等按钮的距离。类似的按钮应按此规则排列分布。

    界面布局还可能发生在窗口最大化和最小化上,有可能窗口缩小的时候没有下拉框或不匹配分辨率,对用户来讲,这个错误实在很低级。有些用户由于操作习惯,非常不喜欢腾出手使用鼠标,尤其是大量输入的界面,因此,要注意设置键盘的快捷方式。还有,按 Tab定位到下一焦点时要注意顺序,避免跳转太灵活而让操作人员感到无从适应,在界面进行维护或者修改的时候,不要忘了软件测试开发人员是否无意改变了这些快捷方式和跳转顺序。

    10、版本和补丁包的环境问题

    理论上讲,这属于兼容性测试应该覆盖的问题。有些客户很喜欢更新最新的软件版本或者微软时不时打些补丁包,问题就出现了。有时候升级不一定是好事。这些问题最好在测试的时候增加几个用例,多用不同软件版本的机器跑一跑。软件测试有个定律是:你没跑过的地方,就一定会出事。经常听到开发人员抱怨,怎么我的机器没问题,你的机器就有事了呢?这不能完全靠配置管理员解决问题,环境配置项是大家最容易忽略的。

    11、用户管理缺陷

    用户管理的角色和授权需要好好研究一下,作过测试的人员都知道,有时候为了测试的方便,测试用户都是具有超级权限的用户。而且,比较容易忽略用户管理这一部分的测试。往往发往客户的时候,很多测试用户都没有删除。

    另外,有些接口的用户和口令,到软件使用寿命结束都没有更改过。在一次测试中,软件测试人员发现,给一个用户授超级用户权限,之后更改这个用户为受限权限。使用中发现,用户居然没有真正回收权限,用户管理界面上没有任何不对。及早准备用户管理用例,不要等到测试快结束时候才想起。

    12、常识缺陷

    从逻辑或者统计学上讲,计算机是允许如此处理的,但是从常识上来讲,这些情况不可能发生。例如电话号码不可能出现小数点,终止时间不能大于开始时间等等。除此之外,常识还要结合业务特点来进行判断,因此,开发和测试人员要格外注意对自己知识的培养以及增加对需求细节的了解。不能因为一味追求进度而采用最简单的代码来实现,对用户来说,这些错误可能是很荒谬的。

    尽管我们不可能完美的测试一个软件,但是我们仍然可以改进我们的软件测试。每次测试结束,及时总结测试中的不足,进一步完善用例。思考一下那些容易忽略的软件缺陷,能提高对软件测试的认识,提高所在组织软件的质量。

382/2<12
Open Toolbar