📄 d_o_h_ unit testing the dojo toolkit.mht
字号:
<P>Note that in the above example, the runTest function =
<EM>explicitly</EM>=20
returns a <CODE class=3D"geshifilter javascript">doh.<SPAN=20
class=3Dme1>Deferred</SPAN></CODE> object. This is how the system knows =
that you=20
are going to be testing potentially asynchronous conditions. Also, in =
our=20
delayed call (see the setTimeout), we explicitly catch errors and pass =
them to=20
the Deferred's <CODE class=3D"geshifilter javascript">errback<SPAN=20
class=3Dbr0>(</SPAN><SPAN class=3Dbr0>)</SPAN></CODE> function. It is =
expected that=20
your code will do this if you are testing asynchronous conditions. =
Lastly, you=20
may specify a timeout in milliseconds as part of the fixture object. =
</P>
<P>As with the previous examples, you can specify an anonymous or single =
function in place of a the full fixture used here to handle asynchronous =
cases.=20
The only caveat is that it must return a Deferred object in order to be =
treated=20
as an async test. We can also simplify the above by using the =
tests.Deferred=20
classes getTestCallback() method. Here's a simplified async test case: =
</P>
<DIV class=3Dgeshifilter style=3D"FONT-FAMILY: monospace">doh.<SPAN=20
class=3Dme1>register</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN=20
class=3Dst0>"tests.moduleToBeTested"</SPAN>, <SPAN =
class=3Dkw2>function</SPAN>=20
simplerAsyncTest<SPAN class=3Dbr0>(</SPAN><SPAN =
class=3Dbr0>)</SPAN><SPAN=20
class=3Dbr0>{</SPAN><BR> <SPAN =
class=3Dkw2>var</SPAN>=20
testCondtition =3D <SPAN class=3Dkw2>true</SPAN>;<BR> =
=20
<SPAN class=3Dkw2>var</SPAN> d =3D <SPAN class=3Dkw2>new</SPAN> =
doh.<SPAN=20
class=3Dme1>Deferred</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN=20
class=3Dbr0>)</SPAN>;<BR> <SPAN =
class=3Dkw2>var</SPAN>=20
checkCondition =3D <SPAN class=3Dkw2>function</SPAN><SPAN =
class=3Dbr0>(</SPAN><SPAN=20
class=3Dbr0>)</SPAN><SPAN class=3Dbr0>{</SPAN><BR> =
=20
doh.<SPAN class=3Dme1>assertTrue</SPAN><SPAN=20
class=3Dbr0>(</SPAN>testCondition<SPAN class=3Dbr0>)</SPAN>;<BR> =
=20
<SPAN class=3Dbr0>}</SPAN>;<BR> =
setTimeout<SPAN=20
class=3Dbr0>(</SPAN>d.<SPAN class=3Dme1>getTestCallback</SPAN><SPAN=20
class=3Dbr0>(</SPAN>checkCondition<SPAN class=3Dbr0>)</SPAN>, <SPAN=20
class=3Dnu0>100</SPAN><SPAN class=3Dbr0>)</SPAN>;<BR> =
=20
<SPAN class=3Dkw1>return</SPAN> d;<BR><SPAN class=3Dbr0>}</SPAN><SPAN=20
class=3Dbr0>)</SPAN>;</DIV>
<P>While the test case still needs to pass back a Deferred object, the =
use of=20
the getTestCallback() to wrap the success or failure test function =
allows us to=20
stop manually handling exceptions that might be thrown in the callback =
function,=20
specifically from assertTrue(), assertEqual(), or assertFalse(). </P>
<H3>Group Registration</H3>
<P>Many times, it's advantageous to register an entire group of tests at =
once.=20
D.O.H. provides a method for doing this as well as for registering =
group-level=20
<CODE class=3D"geshifilter javascript">setUp</CODE> and <CODE=20
class=3D"geshifilter javascript">tearDown</CODE> methods. The <CODE=20
class=3D"geshifilter javascript">tests.<SPAN =
class=3Dme1>registerGroup</SPAN><SPAN=20
class=3Dbr0>(</SPAN><SPAN class=3Dkw3>name</SPAN>, tests, setUp, =
tearDown<SPAN=20
class=3Dbr0>)</SPAN></CODE> method lets you handle this in a single =
call:</P>
<DIV class=3Dgeshifilter style=3D"FONT-FAMILY: monospace"><SPAN =
class=3Dco1>// file=20
located in core at:</SPAN><BR><SPAN class=3Dco1>// =20
tests/fullGroupTest.js</SPAN><BR>dojo.<SPAN =
class=3Dme1>provide</SPAN><SPAN=20
class=3Dbr0>(</SPAN><SPAN class=3Dst0>"tests.fullGroupTest"</SPAN><SPAN=20
class=3Dbr0>)</SPAN>;<BR>dojo.<SPAN class=3Dme1>require</SPAN><SPAN=20
class=3Dbr0>(</SPAN><SPAN class=3Dst0>"tests.runner"</SPAN><SPAN=20
class=3Dbr0>)</SPAN>;<BR class=3Dgeshibr>doh.<SPAN=20
class=3Dme1>registerGroup</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN=20
class=3Dst0>"tests.fullGroupTest"</SPAN>,<BR> =
<SPAN=20
class=3Dbr0>[</SPAN><BR> =
=20
<SPAN class=3Dco1>// single test, no test fixture</SPAN><BR> =
=20
<SPAN class=3Dkw2>function</SPAN>=20
assertTrueTest<SPAN class=3Dbr0>(</SPAN>t<SPAN class=3Dbr0>)</SPAN><SPAN =
class=3Dbr0>{</SPAN> t.<SPAN class=3Dme1>t</SPAN><SPAN =
class=3Dbr0>(</SPAN><SPAN=20
class=3Dkw2>true</SPAN><SPAN class=3Dbr0>)</SPAN>; <SPAN=20
class=3Dbr0>}</SPAN>,<BR> =
=20
<SPAN class=3Dco1>// string variant of the same:</SPAN><BR> =
=20
<SPAN=20
class=3Dst0>"doh.t(true);"</SPAN>,<BR> =
=20
<SPAN class=3Dco1>// test that uses variable set up by=20
group</SPAN><BR> =
<SPAN=20
class=3Dkw2>function</SPAN> assertTrueTest<SPAN =
class=3Dbr0>(</SPAN>t<SPAN=20
class=3Dbr0>)</SPAN><SPAN class=3Dbr0>{</SPAN><BR> =
=20
t.<SPAN =
class=3Dme1>t</SPAN><SPAN=20
class=3Dbr0>(</SPAN>tests.<SPAN =
class=3Dme1>fullGroupTest</SPAN>._localVariable<SPAN=20
class=3Dbr0>)</SPAN>;<BR> =
=20
<SPAN class=3Dbr0>}</SPAN>,<BR> =
=20
<SPAN class=3Dco1>// ...</SPAN><BR> =
<SPAN=20
class=3Dbr0>]</SPAN>,<BR> <SPAN=20
class=3Dkw2>function</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN =
class=3Dbr0>)</SPAN><SPAN=20
class=3Dbr0>{</SPAN> <SPAN class=3Dco1>// setUp</SPAN><BR> =
=20
tests.<SPAN=20
class=3Dme1>fullGroupTest</SPAN>._localVariable =3D <SPAN=20
class=3Dkw2>true</SPAN>;<BR> <SPAN=20
class=3Dbr0>}</SPAN>,<BR> <SPAN=20
class=3Dkw2>function</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN =
class=3Dbr0>)</SPAN><SPAN=20
class=3Dbr0>{</SPAN> <SPAN class=3Dco1>// tearDown</SPAN><BR> =
=20
tests.<SPAN=20
class=3Dme1>fullGroupTest</SPAN>._localVariable =3D <SPAN=20
class=3Dkw2>false</SPAN>;<BR> <SPAN=20
class=3Dbr0>}</SPAN><BR><SPAN class=3Dbr0>)</SPAN>;</DIV>
<P>Note that when using <CODE=20
class=3D"geshifilter javascript">registerGroup</CODE>, <CODE=20
class=3D"geshifilter javascript">setUp</CODE> and <CODE=20
class=3D"geshifilter javascript">tearDown</CODE> replace existing =
group-level=20
handlers, but the registered tests are additive to any pre-existing =
tests=20
registered for the group. </P>
<P>The above example also introduces yet another shorthand for writing =
tests,=20
the string-only test. This style of test authoring is particularly =
terse. Tests=20
written this way do not provide explicit fixture names and so the test =
code=20
itself is used as the test name in reporting. In these tests, there is =
also=20
always a variable <CODE class=3D"geshifilter javascript">t</CODE> which =
is an=20
alias to the global <CODE class=3D"geshifilter javascript">tests</CODE> =
variable.=20
This allows for very compact tests to be written in the form:</P>
<DIV class=3Dgeshifilter style=3D"FONT-FAMILY: monospace"><SPAN=20
class=3Dbr0>[</SPAN><BR> <SPAN=20
class=3Dst0>"doh.t(true);"</SPAN>,<BR> <SPAN=20
class=3Dst0>"doh.f(!true);"</SPAN>,<BR> <SPAN =
class=3Dst0>"doh.is('thinger', 'thing'+'er')"</SPAN>,<BR> =
=20
<SPAN class=3Dco1>// ...</SPAN><BR><SPAN =
class=3Dbr0>]</SPAN></DIV>
<P>With group registration, this style of test authoring requires very =
little=20
typing. Just mind your string quotes! </P>
<H3>URL-based Testing</H3>
<P>Being developed explicitly to test JavaScript applications, D.O.H. =
includes=20
features for browser-based test harnesses to load sub-documents which =
may run a=20
set of tests explicitly on a browser-provided DOM. This lets you =
automate UI=20
testing and isolate browser-specific bugs by writing tests once and =
quickly=20
running them through the unified test harness UI. To support this, =
browser=20
runtimes for D.O.H. provide an implementation for <CODE=20
class=3D"geshifilter javascript">tests.<SPAN =
class=3Dme1>registerUrl</SPAN><SPAN=20
class=3Dbr0>(</SPAN>groupName, url<SPAN class=3Dbr0>)</SPAN></CODE>. On =
other=20
environments, this may be a no-op. </P>
<P>A real example from Dojo Core: </P>
<DIV class=3Dgeshifilter style=3D"FONT-FAMILY: monospace">doh.<SPAN=20
class=3Dme1>registerUrl</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN=20
class=3Dst0>"tests._base.NodeList"</SPAN>, dojo.<SPAN=20
class=3Dme1>moduleUrl</SPAN><SPAN class=3Dbr0>(</SPAN><SPAN=20
class=3Dst0>"tests"</SPAN>, <SPAN =
class=3Dst0>"_base/NodeList.html"</SPAN><SPAN=20
class=3Dbr0>)</SPAN><SPAN class=3Dbr0>)</SPAN>;</DIV>
<P>This example uses Dojo to normalize the tested URL with relationship =
to the=20
loading code, but you can just as easily specify a full URL manually. =
Just be=20
aware that in order for D.O.H. to be able to record the results of tests =
from=20
this page, it must be hosted on the same domain as the hosting test =
harness.=20
</P>
<P>But what does the page itself look like? Here's a snapshot of the =
page=20
referenced above: </P>
<DIV class=3Dgeshifilter style=3D"FONT-FAMILY: monospace"><SPAN =
class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/html.html"><SPAN=20
class=3Dkw2><html></SPAN></A></SPAN><BR> =
<SPAN=20
class=3Dsc2><A =
href=3D"http://december.com/html/4/element/head.html"><SPAN=20
class=3Dkw2><head></SPAN></A></SPAN><BR> =
=20
<SPAN class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/title.html"><SPAN=20
class=3Dkw2><title></SPAN></A></SPAN>testing dojo.NodeList<SPAN=20
class=3Dsc2><SPAN class=3Dkw2></title></SPAN></SPAN><BR> =
=20
<SPAN class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/script.html"><SPAN=20
class=3Dkw2><script</SPAN></A> <SPAN class=3Dkw3>type</SPAN>=3D<SPAN=20
class=3Dst0>"text/javascript"</SPAN> <SPAN =
class=3Dkw3>src</SPAN>=3D<SPAN=20
class=3Dst0>"../../dojo.js"</SPAN> <BR> =
=20
djConfig=3D<SPAN =
class=3Dst0>"isDebug:=20
true"</SPAN><SPAN class=3Dkw2>></SPAN></SPAN><SPAN class=3Dsc2><SPAN=20
class=3Dkw2></script></SPAN></SPAN><BR> =
=20
<SPAN class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/script.html"><SPAN=20
class=3Dkw2><script</SPAN></A> <SPAN class=3Dkw3>type</SPAN>=3D<SPAN=20
class=3Dst0>"text/javascript"</SPAN><SPAN =
class=3Dkw2>></SPAN></SPAN><BR> =20
=
=20
<SPAN class=3Dsc2><A =
href=3D"http://december.com/html/4/element/b.html"><SPAN=20
class=3Dkw2><b></SPAN></A></SPAN>dojo.require("doh.runner");<SPAN=20
class=3Dsc2><SPAN class=3Dkw2></b></SPAN></SPAN><BR> =
=20
=20
dojo.addOnLoad(function(){<BR> =
=20
=
doh.register("t",=20
<BR> =
=20
=
[<BR> =20
=
=20
=
=20
function ctor(){<BR> =
=20
=
=20
=
var nl =3D=20
new dojo.NodeList();<BR> =
=20
=
=20
=20
nl.push(dojo.byId("c1"));<BR> =
=20
=
=20
=20
doh.assertEqual(1, nl.length);<BR> =
=20
=
=20
},<BR> =
=20
=
=20
// =
...<BR> =
=20
=20
]<BR> =
=20
);<BR> =
=20
=
=20
<SPAN class=3Dsc2><A =
href=3D"http://december.com/html/4/element/b.html"><SPAN=20
class=3Dkw2><b></SPAN></A></SPAN>doh.run();<SPAN class=3Dsc2><SPAN =
class=3Dkw2></b></SPAN></SPAN><BR> =
=20
});<BR> =
=20
<SPAN class=3Dsc2><SPAN=20
class=3Dkw2></script></SPAN></SPAN><BR> =
<SPAN=20
class=3Dsc2><SPAN class=3Dkw2></head></SPAN></SPAN><BR> =
=20
<SPAN class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/body.html"><SPAN=20
class=3Dkw2><body></SPAN></A></SPAN><BR> =
=20
<SPAN class=3Dsc2><A=20
href=3D"http://december.com/html/4/element/h1.html"><SPAN=20
class=3Dkw2><h1></SPAN></A></SPAN>testing dojo.NodeList<SPAN =
class=3Dsc2><SPAN=20
class=3Dkw2></h1></SPAN></SPAN><BR> =
=20
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -