查看: 4054|回复: 12

对 JavaScript 进行单元测试的工具

[复制链接]
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
跳转到指定楼层
1#
发表于 2013-5-17 19:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

简介
单元测试关注的是验证一个模块或一段代码的执行效果是否和设计或预期一样。有些开发人员认为,编写测试用例浪费时间而宁愿去编写新的模块。然而,在处理大型应用程序时,单元测试实际上会节省时间;它能帮助您跟踪问题并安全地更新代码。
常用缩略语
DOM:文档对象模型
HTML:超文本标记语言
JSTD:JSTestDriver
YUI:Yahoo! User Interface
在过去,只对服务器端语言进行单元测试。但前端组件越来越复杂,使得编写 JavaScript 代码测试用例的需求日益提高。如果您不经常编写客户端脚本的测试,学习进度可能非常难。测试用户界面可能需要在思路上做一些调整。(有些程序开发人员一时半会还不能相信 JavaScript 是合适的编程语言。)
在本文中,您将学习如何使用 QUnit、YUI Test 和 JSTestDriver 对 JavaScript 进行单元测试。
下载 本文的源代码。
回页首
JavaScript 单元测试
为了演示 JavaScript 测试,这一节将分析 JavaScript 中一个基本函数测试用例。清单 1 显示了要测试的函数:将 3(作为一个数)添加到传递的变量中。

清单 1. 源代码 (example1/script.js)
                               
function addThreeToNumber(el){
    return el + 3;
}

清单 2 在自执行的函数中包含了测试用例。

清单 2.测试用例 (example1/test.js)
                               
(function testAddThreeToNumber (){
    var a = 5,
        valueExpected= 8;
   
    if (addThreeToNumber (a) === valueExpected) {
        console.log("Passed!");
    } else {
        console.log("Failed!");
    }
}());

将 5 传递给测试的函数之后,测试检查返回值是 8。如果测试成功,就会在一个现有浏览器的控制台中打印出 Passed!;否则就会出现 Failed!。如果要运行测试,需要按照以下步骤进行操作:
将两个脚本文件导入作为测试运行程序的 HTML 页面中,如清单 3 所示。
在浏览器中打开页面。

清单 3. HTML 页面 (example1/runner.html)
                               
<!DOCTYPE html>
<html>
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8">
         <title>Example 1</title>
         <script type="text/javascript" src="js/script.js"></script>
          <script type="text/javascript" src="js/test.js"></script>
     </head>
     <body></body>
</html>

您可以不使用浏览器控制台,而是将结果打印在页面或由 alert() 方法生成的弹出窗口中。
断言是测试用例中的核心元素,用来验证某一条件是否满足。例如,在 清单 2 中,addThreeToNumber (a) === valueExpected 就是一个断言。
如果您拥有很多用例并带有很多断言,那么使用框架就会方便很多。下面的内容将会重点介绍一些最流行的 JavaScript 单元测试框架:QUnit、YUI Test 和 JSTestDriver。
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
2#
 楼主| 发表于 2013-5-17 19:25 | 只看该作者
[size=0.76em]QUnit 入门
[size=0.76em]QUnit 是与 JUnit(Java 编程)类似的单元测试框架,jQuery 团队用它来对 jQuery 库进行单元测试。要使用 QUnit,需要按照以下方法:
  • 下载 qunit.css 文件和 qunit.js 文件(参阅 参考资料)。
  • 创建一个 HTML 页面,其中包含导入刚下载的 CSS 和 JavaScript 文件的特定标签。
[size=0.76em]清单 4 显示了适用于 QUnit 的标准的 HTML 运行程序。

清单 4. HTML 运行程序 (qunit/runner.html)
                                <!DOCTYPE html><html>    <head>        <meta charset="UTF-8" />        <title>QUnit Test Suite</title>        <link rel="stylesheet" href="css/qunit.css" type="text/css" media="screen">        <script type="text/javascript" src="js/lib/qunit.js"></script>    </head>    <body>        <h1 id="qunit-header">QUnit Test Suite</h1>        <h2 id="qunit-banner"></h2>        <div id="qunit-testrunner-toolbar"></div>        <h2 id="qunit-userAgent"></h2>        <ol id="qunit-tests"></ol>        <div id="qunit-fixture">test markup</div>    </body></html>

[size=0.76em]假设您拥有两个函数分别负责将温度从摄氏转换为华氏,并转换回来。清单 5 显示了执行此转换的脚本。

清单 5. 转换 (qunit/js/script.js)
                                function convertFromCelsiusToFahrenheit(c){    var f = c * (9/5) + 32;    return f;}function convertFromFahrenheitToCelsius(f){    var c = (f - 32) * (5/9);    return c;}

[size=0.76em]清单 6 显示了各自的测试用例。

清单 6. 测试用例 (qunit/js/test.js)
                                module ("Temperature conversion")test("conversion to F", function(){    var actual1 = convertFromCelsiusToFahrenheit(20);    equal(actual1, 68, ?Value not correct?);            var actual2 = convertFromCelsiusToFahrenheit(30);    equal(actual2, 86, ?Value not correct?);})test("conversion to C", function(){    var actual1 = convertFromFahrenheitToCelsius(68);    equal(actual1, 20, ?Value not correct?);    var actual2 = convertFromFahrenheitToCelsius(86);    equal(actual2, 30, ?Value not correct?);})

[size=0.76em]QUnit 中的测试用例由 test() 方法定义。逻辑是包含在传入函数的第二个参数中。在清单 6 中,两个测试分别名为 conversion to F 和 conversion to C。每个测试包含两个断言。该测试中的断言使用了 equal() 方法。equal() 函数可以将预期值与测试函数的实际值相比较。equal() 方法中的第三个参数是错误情况下显示的消息。
[size=0.76em]还可以通过 module() 函数将测试组织到模块中。在清单 6 中,Temperature conversion 模块含有这两个测试。
[size=0.76em]如果要运行测试:
  • 在 HTML 运行程序中包含源代码和测试文件,如清单 7 所示。
  • 在浏览器中打开页面。

清单 7. 在运行程序中包含 script.js 和 test.js
                                ...<script type="text/javascript" src="js/script.js"></script><script type="text/javascript" src="js/test.js"></script>...

[size=0.76em]图 1 显示了 QUnit 如何在浏览器 (Firefox) 中显示结果。

图 1. QUnit 结果

[size=0.76em]清单 6 中的断言使用了 equal() 方法,但它不是 QUnit 提供的惟一断言。QUnit 提供的其他断言包括 ok() 或 strictEqual()。清单 8 显示了正在执行的方法。

清单 8. 更多的断言
                                module ("Other assertion");test("assertions", function(){    ok(true);    ok(3);    strictEqual("c", "c");    equal (3, "3");});

[size=0.76em]ok() 函数检查第一个参数为 true;strictEqual() 验证第一个参数严格等于第二个参数。在这些代码背后,strictEqual() 使用了 === 运算符,equal() 使用了 == 运算符。
[size=0.76em]如果测试失败,QUnit 还提供了有用的信息。将清单 8 中的代码改成清单 9 中的代码,让上一次断言执行失败。

清单 9. 上一次断言出现的错误
                                module ("Other assertion");test("assertions", function(){    ok(true);    ok(3);    strictEqual("c", "c");    strictEqual (3, "3");});

[size=0.76em]图 2 显示了 QUnit 执行清单 9 代码所返回的结果。

图 2. QUnit 结果:上次测试失败

[size=0.76em]结果非常详细,而且很容易查到上次断言的预期值与实际值有什么不同。
[size=0.76em]QUnit 另一项特性能让您在模块中的所有测试执行之前或之后执行命令。module() 函数接受 setup() 和 teardown() 回调作为第二个参数。使用 setup() 函数更新 清单 6,如清单 10 所示。

清单 10. setup() (qunit/js/test-setup.js)
                                module ("Temperature conversion", {    setup : function() {        this.celsius1 = 20;        this.celsius2 = 30;                        this.fahrenheit1 = 68;        this.fahrenheit2 = 86;    }});test("conversion to F", function(){    var actual1 = convertFromCelsiusToFahrenheit(this.celsius1);    equal(actual1, this.fahrenheit1);            var actual2 = convertFromCelsiusToFahrenheit(this.celsius2);    equal(actual2, this.fahrenheit2);});test("conversion to C", function(){    var actual1 = convertFromFahrenheitToCelsius(this.fahrenheit1);    equal(actual1, this.celsius1);            var actual2 = convertFromFahrenheitToCelsius(this.fahrenheit2);    equal(actual2, this.celsius2);});

[size=0.76em]该示例移动了设置部分的断言所使用的值,以避免在测试的逻辑中使用这些值。
[size=0.76em]QUnit 还通过 asyncTest() 函数提供对异步测试的支持,如果您使用 Asynchronous JavaScript and XML (Ajax),这是非常有用的特性。在这样的环境中,expect() 函数可以让你轻松地验证测试中运行的断言数量。

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
3#
 楼主| 发表于 2013-5-17 19:25 | 只看该作者
[size=0.76em]YUI Test:独立的单元测试模块
[size=0.76em]YUI Test 是 YUI 库(Yahoo!)的一个组件,是一个可扩展而完整的单元测试框架。如果要使用 YUI Test,需要:
  • 将 YUI 导入 HTML 运行程序,如下所示。
    <script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>


    如以上代码所示,此样例使用了 YUI Test 第 3 版本。
  • 在测试脚本文件中,实例化 YUI 函数。加载所需的模块,test 和 console,如清单 11 所示。

清单 11.下载 test 和 console YUI 模块
                                YUI().use("test", "console", function (Y) {     // Test cases go here});

[size=0.76em]test 模块显然是用于测试的。console 模块并不是强制性的,但本示例将用它来打印结果。测试用例将会进入回调中,并以全局的Y 实例作为参数。
[size=0.76em]YUI Test 使用 Y.Test.Case() 构造函数实例化新测试用例,使用 Y.Test.Suite() 构造函数来实例化测试套件。测试套件与 JUnit 类似,包含若干个测试用例。可以使用 add() 方法将测试用例添加到测试套件中。
[size=0.76em]我们使用 YUI test 重新测试 清单 5 中的源代码。清单 12 显示了如何创建测试用的套件和测试用例。

清单 12. 测试套件和用例
                                YUI().use("test", "console", function (Y) {             var suite = new Y.Test.Suite("Temperature conversion suite");     //add a test case     suite.add(new Y.Test.Case({         name:"Temperature conversion?     )); });

[size=0.76em]清单 12 生成了一个名为 Temperature conversion suite 的套件和一个名为 Temperature conversion 的测试用例。现在,可以将测试方法写入对象文本中,作为参数传递给 Y.Test.Case 构造函数,如清单 13 所示。

清单 13. 测试用例与测试方法
                                suite.add(new Y.Test.Case({    name:"Temperature conversion",    setUp : function () {        this.celsius1 = 20;        this.celsius2 = 30;                        this.fahrenheit1 = 68;        this.fahrenheit2 = 86;    },    testConversionCtoF: function () {        Y.Assert.areEqual(this.fahrenheit1,         convertFromCelsiusToFahrenheit(this.celsius1));                Y.Assert.areEqual(this.fahrenheit2, convertFromCelsiusToFahrenheit(this.celsius2));    },                    testConversionFtoC: function () {        Y.Assert.areEqual(this.celsius1,convertFromFahrenheitToCelsius(this.fahrenheit1));                                Y.Assert.areEqual(this.celsius2, convertFromFahrenheitToCelsius(this.fahrenheit2));    }}));

[size=0.76em]您可能注意到,在清单 13 中:
  • 可使用 setUp() 方法。YUI Test 在测试用例和测试套件层提供了 setUp() 和 tearDown() 方法。
  • 测试方法名以 test 单词开头,它们包含断言。
  • 本示例使用 Y.Assert.areEqual() 断言类型,它与 QUnit 中的 equal() 函数类似。
    [size=1em]YUI Test 为断言提供了多种方法,如:
    • Y.Assert.areSame(),它类似于 QUnit 中的 strictEqual()。
    • 数据类型断言(Y.Assert.isArray()、Y.Assert.isBoolean()、Y.Assert.isNumber() 等等)。
    • 特殊值断言(Y.Assert.isFalse()、Y.Assert.isNaN()、Y.Assert.isNull() 等等)。

[size=0.76em]要启动 YUI 中的测试,需要使用 Y.Test.Runner 对象。还需要将套件或测试用例添加到对象中,然后调用 run() 方法来运行测试。清单 14 显示了如何运行 清单 13 中创建的测试。

清单 14. 运行 YUI test
                                Y.Test.Runner.add(suite);Y.Test.Runner.run();

[size=0.76em]在默认情况下,结果会打印在浏览器的控制台中(如果浏览器支持控制台的话)。更好的方法是使用 Yahoo! Console 组件来打印结果。如果要使用 Yahoo! Console 组件,需要采用 Y.Console 构造函数将控制台绑定到 HTML 运行程序的 DOM 元素中,如清单 15 所示。

清单 15. Yahoo! Console
                                var console = new Y.Console({    verbose: true,    newestOnTop: false,    width:"600px"});console.render('#testLogger');

[size=0.76em]清单 15 显示了如何使用几个参数配置控制台。该控制台会在 DOM 元素内部呈现,其 id 为 testLogger。
[size=0.76em]需要更新 HTML 运行程序。添加该控制台所引用的 DOM 元素,如清单 16 所示。

清单 16. 更新后的 HTML 运行程序支持 Yahoo!Console
                                <body class="yui3-skin-sam">     <div id="testLogger"></div> </body>

[size=0.76em]本例为 <body> 设置了一个类,名为 yui3-skin-sam。该类负责定义控制台的皮肤。
[size=0.76em]图 3 显示了运行测试之后的控制台。

图 3. YUI Test 结果

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
4#
 楼主| 发表于 2013-5-17 19:26 | 只看该作者
[size=0.76em]使用 JSTestDriver 轻松测试
[size=0.76em]通过使用功能强大的 JSTestDriver (JSTD) 工具,您能够在多个浏览器中从命令行运行 JavaScript。JSTD 带有一个 JAR 文件,它可以让您启动服务器、捕获一或多个浏览器并在这些浏览器中运行测试。因为拥有上述的两个框架,您不需要 HTML 运行程序,但您需要一个配置文件。图 17 显示了配置文件。

清单 17. 配置文件 (jsTestDriver.conf)
                                server: http://localhost:4224load:  - js/src/*.jstest:  - js/test/*.js

[size=0.76em]该配置文件是用 YAML 编写的,这是一种很好的配置文件格式。它包含了要启动的服务器以及源代码和测试文件的位置信息。
[size=0.76em]要使用 JSTD 来执行测试:
  • 启动测试服务器。从命令行中,进入到保存 jsTestDriver.jar 的文件夹,并执行以下命令:
    java -jar JsTestDriver-1.3.3d.jar -port 4224


    [size=1em]清单 17 中指定的端口应该与配置文件中指定的一样。在默认情况下,JSTD 会在 JAR 文件所在的同一个目录下查找 jsTestDriver.conf 文件。
  • 在测试中,通过将 URL http://localhost:4224/capture 复制粘贴到测试中的浏览器,在服务器上注册一个或多个浏览器。
[size=0.76em]测试之前示例中所使用的相同代码(清单 5),但这次使用 JSTD 语法。清单 18 显示了如何转换 清单 10 的 QUnit 和 清单14 的 YUI Test 中的代码。

清单 18. JSTD 测试
                                TestCase("Temperature conversion", {    setUp : function () {        this.celsius1 = 20;        this.celsius2 = 30;                this.fahrenheit1 = 68;        this.fahrenheit2 = 86;    },    testConversionCtoF: function () {        assertSame(this.fahrenheit1, convertFromCelsiusToFahrenheit(this.celsius1));        assertSame(this.fahrenheit2, convertFromCelsiusToFahrenheit(this.celsius2));    },            testConversionFtoC: function () {        assertSame(this.celsius1, convertFromFahrenheitToCelsius(this.fahrenheit1));        assertSame(this.celsius2, convertFromFahrenheitToCelsius(this.fahrenheit2));    }});

[size=0.76em]清单 18 中的代码与 YUI 版本差别不大。JSTD 使用 TestCase() 函数来定义测试用例。您可以使用内联声明来定义测试方法,如清单 18 所示,或者可以扩展 TestCase 实例的原型。每个测试用例还可以使用 SetUp() 和 tearDown() 方法。
[size=0.76em]如果要运行测试,运行以下命令:
java -jar JsTestDriver-1.3.3d.jar --tests all

[size=0.76em]图 4 显示了终端上的输出结果。

图 4. JSTD 测试的结果

[size=0.76em]测试会传入之前捕获到的所有浏览器(Chrome 15、Safari 5 和 Firefox 7)。
[size=0.76em]JSTD 还能与您偏好的连续集成系统很好地集成,成为连续版本的一部分。它还能与 IDE 集成,如 Eclipse(插件)或 TextMate(包)。

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
5#
 楼主| 发表于 2013-5-17 19:26 | 只看该作者
结束语
随着现在对 Web 应用程序客户端的关注,对 JavaScript 进行单元测试就显得尤为必要。有很多框架可以帮助您完成此任务,本文介绍了三个最流行的框架:QUnit、YUI Test 和 JSTestDriver。
QUnit 非常简单,很适合初学者的框架。
YUI Test 是个全面的工具,适合熟悉 YUI 库的用户。
JSTestDriver 可在多个浏览器中运行测试。

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
6#
 楼主| 发表于 2013-5-27 19:49 | 只看该作者
企业 Linux 开源系统下的邮件传递代理(Mail Transfer Agent)通常使用 Sendmail,该系统几乎在任何 UNIX 平台上都有相应的版本。另外,还有 D.J. Bernstein 的 Qmail 以及 Wietse Venema 的 Postfix 系统。它们负责接收并转递邮件。这虽然看起来很简单,实际上设置可能相当复杂。在邮件策略管理时需要设置一系列的路由和伪装选项,而许多功能是由语言编程实现的,用以过滤或者修改中继消息的头信息。此外邮件路由和寻址邮件存储信箱的过程包含了复杂的与各种目录服务交互操作,这些目录服务可能包括 DNS、密码文件、NIS、LDAP 别名 / 数据库管理文件,以及各种的通用数据库系统。
如今的 MTA 还要实现反垃圾邮件功能,控制邮件头的 to 和 from 地址格式,达到允许或者限制特定域名或者地址范围目的,以上主要是通过修改存取控制表和规则实现的。这一过程通常包括查询数据表或者目录服务,例如 Paul Vixie 的实时黑洞列表程序 RBL,邮件滥用预防系统 MAPS,以及同类的 Dorkslayer/ORBS 系统。MTA 一直在不断增强之中,以实现加强的策略控制以及反病毒和反蠕虫等功能。
在大多数情况下,安装和设置 MTA 系统比较容易,不过强大功能的实现是以高度复杂性为代价的。如果用户所在的机构选择定制的 MTA 来满足特定的路由、体系、安全性和反垃圾邮件等要求,就需要更加复杂的设置选项,配置包括设计并处理 MTA 和各种子系统如 LDAP、DNS 服务器之间的复杂关系。
众多的 MTA 软件中,最为有影响的应该是 Sendmail、Qmail 和 Postfix。Sendmail 是最古老的 MTA 之一,也拥有一批固定的使用者;Qmail 是新生一代的 MTA 代表,其特点是速度快、体积小,并且容易配置安装。Postfix 起源于 1996 年,它采用模块化设计,使用了大量优秀的技术,以达到安全高效的目的。Postfix 发展到现在已经成为功能非常丰富、扩展性和安全性非常强的优秀 MTA 软件。
首先谈谈 Sendmail。MTA 软件的很多先进功能都是在 Sendmail 上最先实现的。但 Sendmail 也有典型的历史问题,主要是整个程序的没有实现良好的模块化,运行时需要 SID 权限,以及配置文件复杂难懂。这些是阻碍 Sendmail 更好普及应用的一些客观问题。
接着是 Qmail。Qmail 是新生一代的 MTA 代表,实现了模块化设计,避免了 SID 问题,基本功能齐全,配置较 Sendmail 简单,而且用户也很广泛。但 Qmail 最近几年的开发工作基本停止,补丁程序也相对零乱,这些都是长期使用 Qmail 的用户或者邮件服务提供商不得不认真考虑的问题。另外,Qmail 的扩展性并不是很好,经常需要补丁来完成功能的扩展。
最后介绍 Postfix。Postfix 是新生一代的 MTA 代表,它以速度快、体积小、易配置安装等特性而著称。Postfix 在设计上可以说是最为优美的,其实现了良好的模块化,邮件的处理流程是通过调用各个功能模块来完成,在效率、功能、可用性、扩展及安全等方面都考虑得比较充分。Postfix 以替代 Sendmail 为目的,并提供了一个更安全、更高性能的灵活的体系。它同样也采用模块化设计,使用了大量优秀的技术,以达到安全的目的。由于作者的设计理念独到,经过 7、8 年时间,Postfix 现今已发展成为功能非常丰富,扩展性和安全性强的优秀 MTA。

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
7#
 楼主| 发表于 2013-5-27 19:49 | 只看该作者
一旦安装并设置完成了 MTA,还要对 MSA 系统进行同样的配置过程。如今大多数机构并不直接将邮件传送到桌面客户系统,而是将邮件存储到服务器,让用户通过 POP 或者 IMAP 来读取各自的邮件。
邮件存储的管理有许多种协议,但如今最常用的是 POP3 和 IMAP4。对于 MTA 来说,由一些程序,或者称之为 Daemon(守护进程)来实现相应协议的服务。大多数 MSA(Mail Submission Agent)可以与通用的 MTA 交互,此外这些系统还包含加锁或者其他安全机制,使得多个 MSA 可以并行工作而不发生冲突。
这意味着一些用户可以通过 POP 协议获取邮件、同时其余一些用户可以使用 IMAP 协议,而另外一些用户可以登录系统,使用本地邮件客户代理例如 Pine、Mutt 或者 Elm 处理邮件。单独用户也可以从一种存取协议切换到另一种,而并不需要系统管理员的干预。在一个已经安装了 Linux 系统机器上设置 POP 服务相当容易,甚至不需要什么操作。通常 POP Daemon 在最初的 Linux 操作系统安装时已经设立,IMAP 也是如此。POP 将邮件转递到客户端并从服务器上移除,而 IMAP 允许用户将邮件存贮在服务器端的文件夹中,而客户端的拷贝是缓存或者工作副本,这样做需要更多的服务器存储空间,却可以让 IT 部门集中在服务器端进行备份和恢复,并让客户端保持相当的灵活性和安全性。IMAP 也可以设置成像 POP 那样在客户端读取后就删除服务器端的邮件,从操作上讲,两者并没有什么不同。

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
8#
 楼主| 发表于 2013-5-27 19:50 | 只看该作者
endmail.cf 是 Sendmail 的配置文件。一般来说在安装了 Linux 系统之后,将自动生成一个适合本系统使用的 sendmail.cf 文件,而且在 sendmail.8.9.3/cf 目录下还有许多适应各种系统的 sendmail.cf 的文件样本,根据文件名也可以判断出它们所适用的场合。可以选择它们替换原有的 sendmail.cf 文件,也就是说,将它们复制到 /etc 目录中去,覆盖掉原来的 sendmail.cf 文件。而且 Sendmail 还提供了一个 sendmail.cf 的生成器 m4,其通过一系列的人机对话来生成一个用户定制的 sendmail.cf 文件。具体的用法可以阅读 m4 的帮助文档,在此就不再详述。
配置文件 sendmail.cf 中的信息仍旧是以行为单位。如果行首的第一个字符为“#”,则表示该行为注释,如果第一个字符为空格则表示该行为上一行的延续。此外,行首的第一个字符均为命令,但是命令同变量或值之间没有间隔。这种格式便于 Sendmail 进行分析,但很难阅读。下面介绍 sendmail.cf 配置文件中的命令。
D(定义宏)
命令 D 定义宏并为其赋值。当宏被定义之后,其就负责提供提供其存储的值给 sendmail.cf 文件中其他的命令使用或者直接提供给 Sendmail 使用。宏的名字可以是任何单字符,小写的用于 Sendmail 内部宏,用户创建的宏只能使用大写字母作为名字。一些 Sendmail 的内部宏也在 sendmail.cf 文件里定义。例如下面两行定义了宏 D 和内部宏 n:
DDcs.mit.edu
DnMAILER-DEAMON

则宏 D 的值为 cs.mit.edu,宏 n 的值为 MAILER-DEAMON。要使用宏的值时,必须在宏的名字前面加上符号“$”,以这种形式来引用其值。例如:
#my official host name
Dj$w.$D

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
9#
 楼主| 发表于 2013-5-27 19:50 | 只看该作者
如果宏 w 的值为主机名 moon,此时宏 j 的值就为 moon.cs.mit.edu,这便是本主机的全称名(FQDN)。
C 与 F(定义类)
命令 C 与 F 都是用来定义 Sendmail 的类。所谓类,实际上就是由处理方式相同的多个变量组成的数组。与宏一样,类也使用单字符名字,大小写规则也一样。类可以定义在一行之中,也可以分多行定义,例如,下面的示范为内部类 w 赋值为系统的主机名,而系统可以有多个名字:
Cwmoon sun
Cwearth
Cwlocalhost
命令 F 是从文件中获取类的值,例如,可以把 moon、sun、earth 保存在 sendmail.cw 之中,然后用 F 命令便可以实现同上述命令完全相同的结果:
Fw/etc/sendmail.cw

对类的引用与宏的引用完全一样,事实上宏就是一种类。两者唯一的区别在于:宏只能有一个唯一的值,而类可以有多个值,当然也可以只有一个值。
O(设置选项)
命令 O 是为 Sendmail 的选项赋值,赋给选项的值可以是字符串、整数或布尔值,所有的选项值都是直接由 Sendmail 来使用。注意:这里所说的选项与 Sendmail 使用的命令行参数不一样。通常情况下,不需要修改这些选项。
T(定义可信任的用户)
命令 T 用来定义一组用户列表,这组用户可以使用 Sendmail 命令带 -f 参数来修改用户发出的邮件地址。一般情况下,包含 root、daemon 和 uucp。管理员最好不要随意添加其他的用户,否则这种权限在某些用户手中可能会对系统安全构成威胁。可信任的用户可以在一行或多行中定义,但是被定义的用户必须是 /etc/passwd 中的合法用户。默认是:
Troot
Tdaemon
Tuucp

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
10#
 楼主| 发表于 2013-5-27 19:50 | 只看该作者
P(设置优先级)
Sendmail 使用命令 P 定义不同的优先级来处理进入出局缓冲区的电子邮件。命令 P 定义的值越高,则优先级也越高,缺省的优先级为 0。负优先级的电子邮件是不产生错误信息的,因此在批量发送邮件是应该定义较底的优先级。常用的优先级为:
Pfirst-class=0
Pspecial-delivery=100
Plist=30
Pbulk=-60
Pjunk=-100

如果用户在发送邮件是要指定优先级,则需要在邮件的首部中添加 Precedence,例如:
Precedence:bulk

K(关键文件声明)
特殊的映射可以定义成:Kmapname mapclass arguments。其中,mapname 是可重写规则中使用这个映射的句柄,mapclass 是映射类型的名字,arguments 的解释依赖与映射类型,通常是包含映射的文件名。
V(配置版本级别)
提供与老版本配置文件的兼容性能。
M(定义邮件传输程序)
命令 M 定义邮件传输程序(mailer)的规格 / 详细参数,其形式为:Mname,[field=value]。
Sendmail 并不是直接发送各种各样的电子邮件,它首先将要发送的邮件分类,然后交给相应的 mailer 来发送,本身只发送基于 SMTP/TCP/IP 的邮件。其中,[IPC] 表示使用 Sendmail 通过 SMTP 来传送邮件。关于 IPC mailer,在 Sendmail 的文档里有一段特殊的解释:当规则集 0 解析到 IPC mailer 时会处理一些特殊的过程。比如直接用 IP 地址发送邮件可以用 [128.32.149.78] 的形式,若用 [ucbvax.berkeley.edu] 将会被作为字符串传递,用这样的方法用户可以构造一个特殊的邮件地址,使自己的邮件按指定的路线发送,而通常用户是不关心也不知道自己邮件的发送路线的。
H(定义邮件的首部格式)
命令 H 定义 Sendmail 命令插进电子邮件首部的行的格式。
R(定义重写规则)
重写规则是 Sendmail 配置文件的核心内容,每一个重写规则由命令 R 定义,其形式如下:
Rpattern transformation comment

命令 R 中的字段由制表符进行分隔,系统处理时忽略注释字段(comment),模式字段(pattern)与改写字段(transformation)为该命令的核心。重写规则将输入地址与模式进行匹配,如果匹配,则将该地址用规则中改写字段的规则重写为新的格式。每一个规则都可以多次处理同一地址,这是因为地址在重写之后,仍要再次同该模式进行匹配,如果仍旧匹配则再次改写,直到不再匹配为止(使用“$:”可以避免无限循环)。
S(设置重写规则集)
规则集是一组可以用数字来引用的相关重写规则。命令 S 是规则集的开始并赋予其一个数字以便由邮件传输程序来调用。规则集可以被看作用来处理电子邮件地址的子程序或函数。具有特殊功能并可由 sendmail 直接调用的规则集有 5 个:
规则集 3:为最大最复杂的规则集,也是用于地址的第一个规则集。它将地址转化为正规形式,如:user@host.domain
规则集 0:应用于传输邮件的地址。必须在规则集 3 之后使用,并仅用于实际邮件传输中接收者的地址。其可以将地址解析成(mailer,host,user)的形式,由邮件传输者、接收方主机和接收用户的名字组成。
规则集 1:应用于消息中所有发送者地址。
规则集 2:应用于消息中所有接收者地址。
规则集 4:应用于消息中所有地址并将内部地址格式转化为外部地址格式。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表