📄 sect03.htm
字号:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_109">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To perform black-box tests using the
unit-testing framework presented in this book, all you need to do is create your
test class as a global class instead of an inner class. All the other rules are
the same (for example, the unit test class must be <B>public</B>, and derived
from <B>UnitTest</B>).
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_110">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There’s one other caveat, which
will also provide a little review of Java packages. If you want to be completely
rigorous, you must put your black-box test class in a separate directory than
the class it tests, otherwise it will have package access to the elements of the
class being tested. That is, you’ll be able to access <B>protected</B> and
<B>friendly</B> elements of the class being tested. Here’s an example:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_111">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c02:Testable.py
<font color=#0000ff>class</font> Testable:
private void f1():
<font color=#0000ff>def</font> f2(self): # <font color=#004488>"Friendly"</font>: package access
<font color=#0000ff>def</font> f3(self): # Also package access
<font color=#0000ff>def</font> f4(self):
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Normally, the only method that
should be directly accessible to the client programmer is <B>f4( )</B>.
However, if you put your black-box test in the same directory, it automatically
becomes part of the same package (in this case, the default package since none
is specified) and then has inappropriate access:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_112">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c02:TooMuchAccess.py
<font color=#0000ff>class</font> TooMuchAccess(UnitTest):
Testable tst = Testable()
<font color=#0000ff>def</font> test1(self):
tst.f2() # Oops!
tst.f3() # Oops!
tst.f4() # OK
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can solve the problem by
moving <B>TooMuchAccess.py</B> into its own subdirectory, thereby putting it in
its own default package (thus a different package from <B>Testable.py</B>). Of
course, when you do this, then <B>Testable</B> must be in its own package, so
that it can be imported (note that it is also possible to import a
“package-less” class by giving the class name in the <B>import</B>
statement and ensuring that the class is in your CLASSPATH):
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_113">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c02:testable:Testable.py
package c02.testable
<font color=#0000ff>class</font> Testable:
private void f1():
<font color=#0000ff>def</font> f2(self): # <font color=#004488>"Friendly"</font>: package access
<font color=#0000ff>def</font> f3(self): # Also package access
<font color=#0000ff>def</font> f4(self):
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s the black-box test
in its own package, showing how only public methods may be called:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_114">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c02:test:BlackBoxTest.py
<font color=#0000ff>class</font> BlackBoxTest(UnitTest):
Testable tst = Testable()
<font color=#0000ff>def</font> test1(self):
#! tst.f2() # Nope!
#! tst.f3() # Nope!
tst.f4() # Only public methods available
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the above program is
indeed very similar to the one that the client programmer would write to use
your class, including the imports and available methods. So it does make a good
programming example. Of course, it’s easier from a coding standpoint to
just make an inner class, and unless you’re ardent about the need for
specific black-box testing you may just want to go ahead and use the inner
classes (with the knowledge that if you need to you can later extract the inner
classes into separate black-box test classes, without too much effort).
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_115">Add Comment</A></FONT><A NAME="_Toc534420077"></A><BR></P></DIV>
<A NAME="Heading28"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Running tests</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The program that runs the tests makes
significant use of reflection so that writing the tests can be simple for the
client programmer.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_116">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># test:RunUnitTests.py
# Discovering the unit test
# <font color=#0000ff>class</font> <font color=#0000ff>and</font> running each test.
<font color=#0000ff>class</font> RunUnitTests:
public static void
require(boolean requirement, String errmsg):
<font color=#0000ff>if</font>(!requirement):
System.err.println(errmsg)
System.exit(1)
<font color=#0000ff>def</font> main(self, String[] args):
require(args.length == 1,
<font color=#004488>"Usage: RunUnitTests qualified-class"</font>)
<font color=#0000ff>try</font>:
Class c = Class.forName(args[0])
# Only finds the inner classes
# declared <font color=#0000ff>in</font> the current <font color=#0000ff>class</font>:
Class[] classes = c.getDeclaredClasses()
Class ut = null
<font color=#0000ff>for</font>(int j = 0 j < classes.length j++):
# Skip inner classes that are
# <font color=#0000ff>not</font> derived <font color=#0000ff>from</font> UnitTest:
<font color=#0000ff>if</font>(!UnitTest.<font color=#0000ff>class</font>.
isAssignableFrom(classes[j]))
<font color=#0000ff>continue</font>
ut = classes[j]
<font color=#0000ff>break</font> # Finds the first test <font color=#0000ff>class</font> only
# If it found an inner <font color=#0000ff>class</font>,
# that <font color=#0000ff>class</font> must be static:
<font color=#0000ff>if</font>(ut != null)
require(
Modifier.isStatic(ut.getModifiers()),
<font color=#004488>"inner UnitTest class must be static"</font>)
# If it couldn't find the inner <font color=#0000ff>class</font>,
# maybe it's a regular <font color=#0000ff>class</font> (<font color=#0000ff>for</font> black-
# box testing:
<font color=#0000ff>if</font>(ut == null)
<font color=#0000ff>if</font>(UnitTest.<font color=#0000ff>class</font>.isAssignableFrom(c))
ut = c
require(ut != null,
<font color=#004488>"No UnitTest class found"</font>)
require(
Modifier.isPublic(ut.getModifiers()),
<font color=#004488>"UnitTest class must be public"</font>)
Method[] methods = ut.getDeclaredMethods()
<font color=#0000ff>for</font>(int k = 0 k < methods.length k++):
Method m = methods[k]
# Ignore overridden UnitTest methods:
<font color=#0000ff>if</font>(m.getName().equals(<font color=#004488>"cleanup"</font>))
<font color=#0000ff>continue</font>
# Only public methods with no
# arguments <font color=#0000ff>and</font> void <font color=#0000ff>return</font>
# types will be used as test code:
<font color=#0000ff>if</font>(m.getParameterTypes().length == 0 &&
m.getReturnType() == void.<font color=#0000ff>class</font> &&
Modifier.isPublic(m.getModifiers())):
# The name of the test <font color=#0000ff>is</font>
# used <font color=#0000ff>in</font> error messages:
UnitTest.testID = m.getName()
# A instance of the
# test object <font color=#0000ff>is</font> created <font color=#0000ff>and</font>
# cleaned up <font color=#0000ff>for</font> each test:
Object test = ut.newInstance()
m.invoke(test, Object[0])
((UnitTest)test).cleanup()
catch(Exception e):
e.printStackTrace(System.err)
# Any exception will <font color=#0000ff>return</font> a nonzero
# value to the console, so that
# 'make' will abort:
System.err.println(<font color=#004488>"Aborting make"</font>)
System.exit(1)
# After all tests <font color=#0000ff>in</font> this <font color=#0000ff>class</font> are run,
# display any results. If there were errors,
# abort 'make' by returning a nonzero value.
<font color=#0000ff>if</font>(UnitTest.errors.size() != 0):
Iterator it = UnitTest.errors.iterator()
<font color=#0000ff>while</font>(it.hasNext())
System.err.println(it.next())
System.exit(1)
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><A NAME="_Toc534420078"></A><BR></P></DIV>
<A NAME="Heading29"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Automatically executing tests</H2></FONT>
<DIV ALIGN="LEFT"><P><A NAME="_Toc534420079"></A><BR></P></DIV>
<A NAME="Heading30"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Exercises</H2></FONT>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Install this book’s
source code tree and ensure that you have a <B>make</B> utility installed on
your system (Gnu <B>make</B> is freely available on the internet at various
locations). In <B>TestDemo.py</B>, un-comment <B>test3( )</B>, then type
<B>make</B> and observe the results.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_117">Add Comment</A></FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Modify
TestDemo.java by adding a new test that throws an exception. Type <B>make</B>
and observe the results.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_118">Add Comment</A></FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Modify
your solutions to the exercises in Chapter 1 by adding unit tests. Write
makefiles that incorporate the unit tests.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_119">Add Comment</A></FONT></OL>
<HR><DIV ALIGN="LEFT"><P><A NAME="fn11" HREF="#fnB11">[11]</A><FONT FACE="Georgia">
</FONT><FONT FACE="Georgia">http://www.junit.org</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="fn12" HREF="#fnB12">[12]</A><FONT FACE="Georgia"> I
had originally called this <B>assert()</B>, but that word became reserved in JDK
1.4 when assertions were added to the language.</FONT><BR></P></DIV>
<DIV ALIGN="CENTER">
<FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
[ <a href="Sect02.htm">Previous Chapter</a> ]
[ <a href="javascript:window.location.href = 'Index.htm';">Table of Contents</a> ]
[ <a href="DocIdx.htm">Index</a> ]
[ <a href="Sect04.htm">Next Chapter</a> ]
</FONT>
<BR>
Last Update:12/31/2001</P></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -