- 浏览: 435837 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
fred7510:
死的啊。。不过还是谢了
flex 截图 -
hechuanshan:
flex状态及动画 -
Da嗒_Sunny:
求使用说明
flex图片裁剪 -
wapj23:
...
flex中定制右键菜单 -
lion_leon:
谢谢!帮了我的大忙了!
利用flashvars给flash传值
2001年初,Edward Hieatt开始“移植”JUnit,目的是在浏览器中测试JavaScript。从那以后,JsUnit的下载次数已近10 000次,大约300人加入了JsUnit的新闻组。JsUnit支持一般的xUnit功能,完全用JavaScript编写,如果你习惯使用JUnit 或者类似的xUnit框架,就会发现JsUnit使用起来相当简单直观。
JsUnit也有一些不同的地方:这里也有setUp()和tearDown(),不过现在作为函数,而不是方法;测试函数(而不是测试方法)分成多个测试页(而不是测试用例);另外JsUnit提供了自己的基于HTML的测试运行工具。表6-1对这两个框架做了比较。
表1 JUnit与JsUnit的比较
JUnit JsUnit
Test类扩展 TestCase 测试页包含jsUnitCore.js
测试方法 测试函数
Test类 基于HTML的测试页
TestSuites 基于HTML的测试集
多个测试运行工具 基于HTML/JavaScript的测试运行工具
setUp()和tearDown()方法 setUp()和tearDown()函数
在虚拟机中运行 在浏览器中运行
用Java编写 用JavaScript编写
1 起步
对于JsUnit,起步很简单,只需从JsUnit网站(www.edwardh.com/jsunit/)下载JsUnit zip文件。把这个压缩文件解开,会得到一个jsunit文件夹,可以把Web服务器放在这里,这样整个团队或者整个组织就能更容易地使用JsUnit。 JsUnit的大部分“核心”都在jsunit/app目录中,在这里可以看到jsUnitCore.js、jsUnitTracer.js和 jsUnitTestManager.js,另外还有其他一些文件。如果你想运行具体的JsUnit测试,可以使用testRunner.html来运行 jsunit/tests目录中找到的任何测试页。如果你在使用IntelliJ,而且想具体使用JsUnit,jsunit/intellij目录中包含了需要的所有适当文件。
2 编写测试
用JsUnit编写测试与用JUnit编写测试很相似。测试函数不能有任何参数,必须有一个前缀test,例如testDateValidation()。测试函数包含在一个测试页(test page)中,这类似于JUnit中的一个Test类。测试页必须包含jsUnitCore.js文件,解开JsUnit zip文件后,就会在jsunit/app目录中找到这个文件。包含这个JavaScript文件实际上就是把一个外部JavaScript文件增加到页面中;只需使用脚本元素<script language="JavaScript" src="jsUnitCore.js"></script>来引用这个文件,要记住,如果你的当前目录不是jsunit/app目录,则还需要提供jsUnitCore.js文件的相关路径信息。当然,在测试页中可以包含任意多个其他函数或JavaScript;实际上,把多个 JavaScript函数放在分开的文件中,是一个很好的做法。测试函数也可以放在单独的JavaScript文件中;不过,如果这样做,就需要使用 exposeTestFunctionNames()方法,这样JsUnit才能找到测试函数。实际上,如果需要针对不同的页面内容建立测试,可以把测试函数放在一个单独的文件中,这样能避免复制-粘贴问题带来的痛苦。
一般地,JsUnit会自动发现测试函数,就像JUnit会发现所有测试方法一样。不过,有些操作系统/浏览器不能合作。如果你发现不能如你所愿地发现测试函数,使用exposeTestFunctionNames()方法就能解决这个问题。
断言方法
现在你对测试函数和测试页有一定的了解了,下面需要写一些实际的测试!与用JUnit一样,你可以使用断言方法(assert method)。断言方法是任何单元测试的基本模块,它们只是一些简单的布尔表达式,可以指示一个给定语句为true还是false。断言失败时,就会产生一个错误,这样将得到众所周知的红条。与JUnit不同,JsUnit没有提供那么丰富的断言方法,但是已经足够你测试JavaScript代码了。注意,除了fail()方法的注释外,其他断言方法的注释都是可选的(这与JUnit类似,甚至也“不正确”地把可选参数放在最前面,而不是最后)。
assert([comment], booleanValue)
assertTrue([comment], booleanValue)
assertFalse([comment], booleanValue)
assertEquals([comment], value1, value2)
assertNotEquals([comment], value1, value2)
assertNull([comment], value)
assertNotNull([comment], value)
assertUndefined([comment], value)
assertNotUndefined([comment], value)
assertNaN([comment], value)
assertNotNaN([comment], value)
fail(comment)
要看这些方法怎么用于测试(象征性地从字面了解),只需看JsUnit下载包提供的测试页就行了。JsUnit还提供了一个变量:JSUNIT_UNDEFINED_VALUE,它映射到JavaScript中的undefined变量。
我们说的已经够多的了!下面来看一个简单的测试!这个例子中有一个简单的函数,会让两个数相加,而且有两个测试:一个用于正整数的相加,另一个用于负整数相加。要测试这个函数,先创建一个简单的Web页面,如代码清单1所示,其中包含了jsUnitCore.js文件,另外包含了要测试的函数和测试函数[4]。当然,在生产代码中,可能不能把测试代码与所测试的函数混在一起,但是作为第一次尝试这样做未尝不可。
代码清单1 简单的测试页
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>A Simple Test Page</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript">
function addTwoNumbers(value1, value2) {
return value1 + value2;
}
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
</script>
</head>
<body>
This is a simple test page for addTwoNumbers(value1, value2).
</body>
</html>
运行这些测试会得到图1所示的结果。(后面将更详细地介绍测试运行工具。)
图1 简单测试的结果
显然,不太可能把生产代码(函数)与测试函数混在同一个测试页中。你可能会把生产代码放在一个单独的JavaScript文件中,然后在测试页中包含这个文件。代码清单2就采用了这种方法。
代码清单2 一种更典型的方法
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Another Test Page</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript" src="simpleJS.js"></script>
<script language="JavaScript">
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
</script>
</head>
<body>
This is a simple test page for the simpleJS file.
</body>
</html>
JavaScript文件实际上相当简单,如代码清单3所示。
代码清单3 simple.js
function addTwoNumbers(value1, value2) {
return parseInt(value1) + parseInt(value2);
}
不出所料,结果是一样的(见图2)。
图2 采用典型方法的结果
可以看到,两个测试函数会自动被发现,而且通常都是这样。不过,如果打开测试页,点击Run之后什么也没有发生,可能就需要使用exposeTestFunctionNames(),以确保JsUnit能找到你的测试,如代码清单4所示。
代码清单4 使用exposeTestFunctionNames()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>A Test Page With exposeTestFunctions</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript" src="simpleJS.js"></script>
<script language="JavaScript">
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
function exposeTestFunctionNames() {
var tests = new Array(2);
tests[0] = "testValidArgs";
tests[1] = "testWithNegativeNumbers";
return tests;
}
</script>
</head>
<body>
This is a simple test page that uses exposeTestFunctionNames.
</body>
</html>
如你所愿,这样就能工作了(见图3)。
如果看到如图4中所示的错误消息,说明你可能忘了在测试页中包含jsUnitCore.js,或者文件的路径不对。请检查测试页,再运行一次。
JsUnit也有一些不同的地方:这里也有setUp()和tearDown(),不过现在作为函数,而不是方法;测试函数(而不是测试方法)分成多个测试页(而不是测试用例);另外JsUnit提供了自己的基于HTML的测试运行工具。表6-1对这两个框架做了比较。
表1 JUnit与JsUnit的比较
JUnit JsUnit
Test类扩展 TestCase 测试页包含jsUnitCore.js
测试方法 测试函数
Test类 基于HTML的测试页
TestSuites 基于HTML的测试集
多个测试运行工具 基于HTML/JavaScript的测试运行工具
setUp()和tearDown()方法 setUp()和tearDown()函数
在虚拟机中运行 在浏览器中运行
用Java编写 用JavaScript编写
1 起步
对于JsUnit,起步很简单,只需从JsUnit网站(www.edwardh.com/jsunit/)下载JsUnit zip文件。把这个压缩文件解开,会得到一个jsunit文件夹,可以把Web服务器放在这里,这样整个团队或者整个组织就能更容易地使用JsUnit。 JsUnit的大部分“核心”都在jsunit/app目录中,在这里可以看到jsUnitCore.js、jsUnitTracer.js和 jsUnitTestManager.js,另外还有其他一些文件。如果你想运行具体的JsUnit测试,可以使用testRunner.html来运行 jsunit/tests目录中找到的任何测试页。如果你在使用IntelliJ,而且想具体使用JsUnit,jsunit/intellij目录中包含了需要的所有适当文件。
2 编写测试
用JsUnit编写测试与用JUnit编写测试很相似。测试函数不能有任何参数,必须有一个前缀test,例如testDateValidation()。测试函数包含在一个测试页(test page)中,这类似于JUnit中的一个Test类。测试页必须包含jsUnitCore.js文件,解开JsUnit zip文件后,就会在jsunit/app目录中找到这个文件。包含这个JavaScript文件实际上就是把一个外部JavaScript文件增加到页面中;只需使用脚本元素<script language="JavaScript" src="jsUnitCore.js"></script>来引用这个文件,要记住,如果你的当前目录不是jsunit/app目录,则还需要提供jsUnitCore.js文件的相关路径信息。当然,在测试页中可以包含任意多个其他函数或JavaScript;实际上,把多个 JavaScript函数放在分开的文件中,是一个很好的做法。测试函数也可以放在单独的JavaScript文件中;不过,如果这样做,就需要使用 exposeTestFunctionNames()方法,这样JsUnit才能找到测试函数。实际上,如果需要针对不同的页面内容建立测试,可以把测试函数放在一个单独的文件中,这样能避免复制-粘贴问题带来的痛苦。
一般地,JsUnit会自动发现测试函数,就像JUnit会发现所有测试方法一样。不过,有些操作系统/浏览器不能合作。如果你发现不能如你所愿地发现测试函数,使用exposeTestFunctionNames()方法就能解决这个问题。
断言方法
现在你对测试函数和测试页有一定的了解了,下面需要写一些实际的测试!与用JUnit一样,你可以使用断言方法(assert method)。断言方法是任何单元测试的基本模块,它们只是一些简单的布尔表达式,可以指示一个给定语句为true还是false。断言失败时,就会产生一个错误,这样将得到众所周知的红条。与JUnit不同,JsUnit没有提供那么丰富的断言方法,但是已经足够你测试JavaScript代码了。注意,除了fail()方法的注释外,其他断言方法的注释都是可选的(这与JUnit类似,甚至也“不正确”地把可选参数放在最前面,而不是最后)。
assert([comment], booleanValue)
assertTrue([comment], booleanValue)
assertFalse([comment], booleanValue)
assertEquals([comment], value1, value2)
assertNotEquals([comment], value1, value2)
assertNull([comment], value)
assertNotNull([comment], value)
assertUndefined([comment], value)
assertNotUndefined([comment], value)
assertNaN([comment], value)
assertNotNaN([comment], value)
fail(comment)
要看这些方法怎么用于测试(象征性地从字面了解),只需看JsUnit下载包提供的测试页就行了。JsUnit还提供了一个变量:JSUNIT_UNDEFINED_VALUE,它映射到JavaScript中的undefined变量。
我们说的已经够多的了!下面来看一个简单的测试!这个例子中有一个简单的函数,会让两个数相加,而且有两个测试:一个用于正整数的相加,另一个用于负整数相加。要测试这个函数,先创建一个简单的Web页面,如代码清单1所示,其中包含了jsUnitCore.js文件,另外包含了要测试的函数和测试函数[4]。当然,在生产代码中,可能不能把测试代码与所测试的函数混在一起,但是作为第一次尝试这样做未尝不可。
代码清单1 简单的测试页
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>A Simple Test Page</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript">
function addTwoNumbers(value1, value2) {
return value1 + value2;
}
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
</script>
</head>
<body>
This is a simple test page for addTwoNumbers(value1, value2).
</body>
</html>
运行这些测试会得到图1所示的结果。(后面将更详细地介绍测试运行工具。)
图1 简单测试的结果
显然,不太可能把生产代码(函数)与测试函数混在同一个测试页中。你可能会把生产代码放在一个单独的JavaScript文件中,然后在测试页中包含这个文件。代码清单2就采用了这种方法。
代码清单2 一种更典型的方法
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Another Test Page</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript" src="simpleJS.js"></script>
<script language="JavaScript">
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
</script>
</head>
<body>
This is a simple test page for the simpleJS file.
</body>
</html>
JavaScript文件实际上相当简单,如代码清单3所示。
代码清单3 simple.js
function addTwoNumbers(value1, value2) {
return parseInt(value1) + parseInt(value2);
}
不出所料,结果是一样的(见图2)。
图2 采用典型方法的结果
可以看到,两个测试函数会自动被发现,而且通常都是这样。不过,如果打开测试页,点击Run之后什么也没有发生,可能就需要使用exposeTestFunctionNames(),以确保JsUnit能找到你的测试,如代码清单4所示。
代码清单4 使用exposeTestFunctionNames()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>A Test Page With exposeTestFunctions</title>
<script language="JavaScript" src="../jsunit/app/jsUnitCore.js"></script>
<script language="JavaScript" src="simpleJS.js"></script>
<script language="JavaScript">
function testValidArgs() {
assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2));
}
function testWithNegativeNumbers() {
assertEquals("negative numbers: -2 + -2 is -4", -4,
addTwoNumbers(-2, -2));
}
function exposeTestFunctionNames() {
var tests = new Array(2);
tests[0] = "testValidArgs";
tests[1] = "testWithNegativeNumbers";
return tests;
}
</script>
</head>
<body>
This is a simple test page that uses exposeTestFunctionNames.
</body>
</html>
如你所愿,这样就能工作了(见图3)。
如果看到如图4中所示的错误消息,说明你可能忘了在测试页中包含jsUnitCore.js,或者文件的路径不对。请检查测试页,再运行一次。
评论
2 楼
panda_love
2011-07-30
不错,学习一下
1 楼
kingapex
2008-08-04
补充:
运行testRunner.html时会发现他有 Trace level 项,用于现实我们在测试方法中的日志信息,包含3个函数:
warn(message, [value])
inform(message, [value])
debug(message, [value])
运行testRunner.html时会发现他有 Trace level 项,用于现实我们在测试方法中的日志信息,包含3个函数:
warn(message, [value])
inform(message, [value])
debug(message, [value])
发表评论
-
一个跨平台的DOMContentLoaded的解决方案
2009-03-26 17:22 1759一个跨平台的DOMContentLoaded的解决方案 ... -
遍历某个dom下的子节点
2009-03-24 16:22 2987var wrap = document.getElementB ... -
Extjs Combo连动
2009-03-16 17:29 4548lcombo.html <!DOCTYPE HTML ... -
利用AJAX取头部信息
2009-03-16 10:14 1201//取所有头部信息 xmlhttp.getAllRespons ... -
Extjs的Ajax Request源码流程分析
2009-03-12 10:29 1274图片太大,不让提交,只能使用链接了。 http://king ... -
http status 一览
2009-03-11 17:09 1115<PRE class=java name=&qu ... -
html5参考手册
2009-02-25 14:05 1563原文:http://www.w3school.com.cn ... -
分析yui结合flash的上传组件
2009-02-13 12:44 2023yui上传组件: http://developer.yahoo ... -
利用jsdt调试js
2008-12-18 16:36 22581、下载eclipse的插件,见附件 2、将plugin下的三 ... -
EXT Menu改变Menu的Layer class之后菜单功能失败的解决办法
2008-11-14 11:32 1563ext2中可以改变 Menu的class ,比如不想要前面的竖 ... -
ie的userdata 和 firefox的sessionStorage
2008-11-10 10:38 2537保存客户端数据,ie用userdata firefox用se ... -
js复制,兼容firefox和ie
2008-10-17 14:55 3157setClipboard: function(data, va ... -
解决ie中js生成的图片不显示的问题
2008-09-05 13:09 2217问题:js生成的dialog,而图片却不显示,如:var bu ... -
如何去除点击链接时出现的虚线框
2008-09-01 10:20 1679有时候在一个页面用到收放功能的时候时,总有一个虚线框在触发收放 ... -
转存附件用
2008-08-31 19:02 0test -
淘宝javascript类别多级下拉连动解析和改进
2008-08-31 18:57 3716效果地址:http://search1.taobao.com/ ... -
slice、pop的神奇用法
2008-08-29 14:45 1508slice 要取得一个数组或一个字串的某段时,那就用slice ... -
void(0)的作用
2008-08-26 14:48 1396经常见<a href="javascript: ... -
web前端结构与行为的分离
2008-08-05 17:53 1154web前端结构与行为的分 ... -
解决aptana代码不提示的问题
2008-08-05 11:47 4772都说aptana的代码提示功能很好,可是我的安装上之后怎么也不 ...
相关推荐
6. **覆盖率报告**:虽然 jsUnit 2.2 自身不直接提供代码覆盖率工具,但可以与其他工具(如 Istanbul)结合使用,以分析测试覆盖了代码的哪些部分,帮助开发者识别未被测试的代码。 为了更好地利用 jsUnit 2.2 进行...
**6.2 分析JsUnit** - **JsUnit简介:** - 一种流行的JavaScript单元测试框架。 - 提供了一套API用于编写和运行测试用例。 **6.3 小结** - **总结要点:** - 使用JsUnit等工具进行单元测试。 - 保障...
6.2 分析jsunit 158 6.2.1 起步 159 6.2.2 编写测试 159 6.2.3 运行测试 172 6.2.4 使用标准/定制查询串 177 6.2.5 使用jsunit服务器 181 6.2.6 获得帮助 183 6.2.7 还能用什么? 184 6.3 小结 184 第7章 ...
- **6.2 分析JsUnit** JsUnit是一个JavaScript单元测试框架。这部分将详细介绍如何安装、编写和运行JsUnit测试。 - **6.3 小结** 概括JsUnit在JavaScript代码测试中的作用和价值。 通过以上章节的学习,读者将...
6.2 分析JsUnit:一种JavaScript单元测试框架,用于测试AJAX应用的函数和组件。 6.3 其他测试框架:如QUnit、Mocha等,帮助开发者对AJAX代码进行系统测试。 6.4 性能测试:监控和优化AJAX应用的响应时间和资源消耗...
5. **报表生成**:测试结果以清晰的格式展示,包括成功、失败和忽略的测试,便于分析测试覆盖率和代码质量。 在“plugins”文件夹中,很可能包含了安装到 Eclipse 中所需的插件文件。通常这些文件是 `.jar` 格式,...
JavaScript Unit Testing,通常...同时,了解如何结合其他工具进行代码覆盖率分析和持续集成也是十分重要的。随着JavaScript在Web开发中的广泛应用,掌握JsUnit这样的测试工具将对提升你的开发效率和代码质量大有裨益。
7. **分析和修复**:根据测试结果,分析代码中的问题,修复bug,并重新运行测试以验证修改是否有效。 在实际应用中,JsUnit可以与其他工具(如JSDoc,代码覆盖率工具等)配合使用,以实现更全面的开发流程。通过...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括 XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析 JavaScript调试工具和技术,以及Ajax开发模式...
本书重点介绍Ajax及相关的工具和技术,主要内容包括 XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析 JavaScript调试工具和技术,以及Ajax开发模式...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...
本书重点介绍Ajax及相关的工具和技术,主要内容包括 XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析 JavaScript调试工具和技术,以及Ajax开发模式...
本书重点介绍Ajax及相关的工具和技术,主要内容包括XMLHttpRequest对象及其属性和方法、发送请求和处理响应、构建完备的Ajax开发工具、使用JsUnit测试JavaScript、分析JavaScript调试工具和技术,以及Ajax开发模式和...