如前文所说,2005中建立单元测试模块十分方便快捷,用鼠标在方法名上右击选择即可。实际上,.net在测试工程中自建了一个十分复杂的文件,文件中将使用单元测试的类的所有方法都建立了一个具有完全一样的方法信息的方法,即方法名和参数列表还有返回值都一样的方法。而在单元测试的代码中,主要使用的都是这个文件中的方法,而不是你创建的类中的方法,虽然他们调用起来是一摸一样的。其实想一想,能够在单元测试中可以毫无阻碍的调用类中的私有方法和内部(internal)方法,就不难理解.net为什么要把所有方法都“重写”一遍了。
途中红线框住的就是自动生成的文件。
文件的内容,将自建类中的所有方法“重写”一遍。
// ------------------------------------------------------------------------------
//<autogenerated>
// This code was generated by Microsoft Visual Studio Team System 2005.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//</autogenerated>
//------------------------------------------------------------------------------
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class BaseAccessor {
protected Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject m_privateObject;
protected BaseAccessor(object target, Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type) {
m_privateObject = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target, type);
}
protected BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type) :
this(null, type) {
}
internal virtual object Target {
get {
return m_privateObject.Target;
}
}
public override string ToString() {
return this.Target.ToString();
}
public override bool Equals(object obj) {
if (typeof(BaseAccessor).IsInstanceOfType(obj)) {
obj = ((BaseAccessor)(obj)).Target;
}
return this.Target.Equals(obj);
}
public override int GetHashCode() {
return this.Target.GetHashCode();
}
}
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class tstUn_ProgramAccessor : BaseAccessor {
protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType("tstUn", "tstUn.Program");
internal tstUn_ProgramAccessor(object target) :
base(target, m_privateType) {
}
internal static void Main(string[] args) {
object[] _args = new object[] {
args};
m_privateType.InvokeStatic("Main", new System.Type[] {
typeof(string).MakeArrayType()}, _args);
}
//<autogenerated>
// This code was generated by Microsoft Visual Studio Team System 2005.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//</autogenerated>
//------------------------------------------------------------------------------
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class BaseAccessor {
protected Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject m_privateObject;
protected BaseAccessor(object target, Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type) {
m_privateObject = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target, type);
}
protected BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type) :
this(null, type) {
}
internal virtual object Target {
get {
return m_privateObject.Target;
}
}
public override string ToString() {
return this.Target.ToString();
}
public override bool Equals(object obj) {
if (typeof(BaseAccessor).IsInstanceOfType(obj)) {
obj = ((BaseAccessor)(obj)).Target;
}
return this.Target.Equals(obj);
}
public override int GetHashCode() {
return this.Target.GetHashCode();
}
}
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class tstUn_ProgramAccessor : BaseAccessor {
protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType("tstUn", "tstUn.Program");
internal tstUn_ProgramAccessor(object target) :
base(target, m_privateType) {
}
internal static void Main(string[] args) {
object[] _args = new object[] {
args};
m_privateType.InvokeStatic("Main", new System.Type[] {
typeof(string).MakeArrayType()}, _args);
}
测试用例自动生成的代码。
1 [TestMethod()]
2 public void BearsTest()
3 {
4 Do target = new Do();
5
6 ZLink.ZLink<Known.Man> expected = null;
7 ZLink.ZLink<Known.Man> actual;
8
9 actual = target.Bears();
10
11 Assert.AreEqual(expected, actual, "tstUn.Do.Bears did not return the expected value.");
12 Assert.Inconclusive("Verify the correctness of this test method.");
13 }
2 public void BearsTest()
3 {
4 Do target = new Do();
5
6 ZLink.ZLink<Known.Man> expected = null;
7 ZLink.ZLink<Known.Man> actual;
8
9 actual = target.Bears();
10
11 Assert.AreEqual(expected, actual, "tstUn.Do.Bears did not return the expected value.");
12 Assert.Inconclusive("Verify the correctness of this test method.");
13 }
大家可以看见,第6、7行用到的是基于范型的类,需要在实例化时在尖括号中给出类型。第6行中的Know.Man是命名空间和类名。现在这个用例是毫无问题的,但是当命名空间中存在下划线"_"是,自动生成的代码就会出现问题。比如我现在将命名空间的名字改成"Know_v1",重新建立测试用例,看看自动生成的代码会是什么样子。
F6编译,出现了问题。
1 [TestMethod()]
2 public void BearsTest()
3 {
4 Do target = new Do();
5
6 ZLink.ZLink<Known>.Man expected = null;
7 ZLink.ZLink<Known>.Man actual;
8
9 actual = target.Bears();
10
11 Assert.AreEqual(expected, actual, "tstUn.Do.Bears did not return the expected value.");
12 Assert.Inconclusive("Verify the correctness of this test method.");
13 }
2 public void BearsTest()
3 {
4 Do target = new Do();
5
6 ZLink.ZLink<Known>.Man expected = null;
7 ZLink.ZLink<Known>.Man actual;
8
9 actual = target.Bears();
10
11 Assert.AreEqual(expected, actual, "tstUn.Do.Bears did not return the expected value.");
12 Assert.Inconclusive("Verify the correctness of this test method.");
13 }
现在再看看第六第七行,正确的代码应该是
ZLink.ZLink<Known_v1.Man> expected = null;
看来是生成代码在遇到下划线和尖括号是出现了问题。
所以,当你想使用单元测试时,就尽量避免在命名空间的命名时使用下划线。
或者你也可以完全使用手动编写单元测试代码,但这样有些方法就无法测试,比如私有和内部(internal)方法。