junit 里面的testXXX方法只能定义为 public 的吗?
其自身的 setU平() 和 tearDown()方法是protected 的.
抱歉,刚才解释的时候有一些错误,在runTest中传进去的参数是方法名字,例如
[code="java"]
SimpleTestCase test = new SimpleTestCase("testGetName");
[/code]
如果调用test.run()则会运行testGetName方法,如果存在的话,如果不存在就会抛出NoSuchMethodException异常,getClass().getMethod(fName, (Class[])null)方法只能得到public的方法,但是这里并不是真正决定为什么必须是public的以test开头的方法才能被测试到
一般想要运行一个test case类中所有的test方法时,需要一个runner类,例如junit.textui.TestRunner类,而这些runner会把参数中的TestCase包装到一个TestSuite类中,决定这两个限制的就在TestSuite中(这次是肯定的)
在TestSuite的这个构造器中(所有其他构造器都会调用这个)
[code="java"]
public TestSuite(final Class<? extends TestCase> theClass)
[/code]
有段代码会通过反射解析传进来的对象,以获得需要测试的方法集(注:单独测试一个方法直接用TestCase.run()就可以做到,象开始的那段代码,而自动获得所有test开头的方法就是在这里)
[code="java"]
while (Test.class.isAssignableFrom(superClass)) {
for (Method each : superClass.getDeclaredMethods())
addTestMethod(each, names, theClass);
superClass= superClass.getSuperclass();
}
[/code]
构造器中会获得对象所有的方法(注:Class.getDeclaredMethods()返回所有public, protected和private的方法,具体的请看JDK),但是在addTestMethod方法中过滤了不满足要求的
[code="java"]
private void addTestMethod(Method m, List names, Class<? extends TestCase> theClass) {
if (! isPublicTestMethod(m)) {
if (isTestMethod(m))
addTest(warning("Test method isn't public: "+m.getName()));
return;
}
}
[/code]
isTestMethod方法代码如下
[code="java"]
private boolean isTestMethod(Method m) {
return
m.getParameterTypes().length == 0 &&
m.getName().startsWith("test") &&
m.getReturnType().equals(Void.TYPE);
}
[/code]
看到hard code的代码了吧,符合测试条件的代码是:没有参数,没有返回值并且以test开头方法,而isPublicTestMethod方法则过滤了不是public的方法
[code="java"]
private boolean isPublicTestMethod(Method m) {
return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
}
[/code]
如果有一个不是public但是符合测试方法名字的方法存在,则只是添加了一个警告信息,方法不会被调用。由于isTestMethod方法是private的,所以不能override
[quote]junit 里面的testXXX方法只能定义为 public 的吗?[/quote]
当然可以定义为protected,private的,只不过只能在其它被测试的testXXX或者子类中调用,不能被JUnit显式测试。
如果你可以查看junit的源代码的话,建议看下TestCase.runBare(),其实一个test case被调用到最后会被TestResult调用其自己的runBare方法来运行,runBare方法的代码如下
[code="java"]
public void runBare() throws Throwable {
Throwable exception= null;
setUp();
try {
runTest();
} catch (Throwable running) {
exception= running;
}
finally {
try {
tearDown();
} catch (Throwable tearingDown) {
if (exception == null) exception= tearingDown;
}
}
if (exception != null) throw exception;
}
[/code]
所有的test case方法都可以继承这个方法,一般不会override它,override了的不在这里讨论了。
从代码可以看出,它自己会调用自己的setUp和tearDown,所以他们是protected就够了,必须要能让子类override.
而我们写的测试方法必须为test开头的public方法的原因在runTest方法里
[code="java"]
Method runMethod= null;
try {
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
try {
runMethod.invoke(this);
}
[/code]
这里只是runTest的节选部分,TestCase类会自己调用反射方法获得以test开头的public方法,这个是由getClass().getMethod(fName, (Class[])null)决定的,所以我们写的测试方法要以test开头,使用public级别
关于test suite,其实质还是调用我们传进去的testcase自己的方法,所以和上面一样,如果你自己override这几个方法,你就可以有自己来定义规则了,当然前提是把它的逻辑理解清楚了
这个只是TestCase的实现,一般我们也都是用这个,其他的实现没有去深究