我正在开发一个大型项目,其中一个基类有数千个派生自它的类(多个开发人员正在研究它们)。期望每个类重写一组方法。我首先使用符合可接受模式的代码模板生成了这些数千个类文件。我现在正在编写单元测试,以确保开发人员没有偏离这种模式。以下是生成的示例类:
// Base class.
public abstract partial class BaseClass
{
protected abstract bool OnTest ();
}
// Derived class. DO NOT CHANGE THE CLASS NAME!
public sealed partial class DerivedClass_00000001: BaseClass
{
/// <summary>
/// Do not modify the code template in any way.
/// Write code only in the try and finally blocks in this method.
/// </summary>
protected override void OnTest ()
{
bool result = false;
ComObject com = null;
// Declare ALL value and reference type variables here. NOWHERE ELSE!
// Variables that would otherwise be narrowly scoped should also be declared here.
// Initialize all reference types to [null]. [object o;] does not conform. [object o = null;] conforms.
// Initialize all value types to their default values. [int x;] does not conform. [int x = 0;] conforms.
try
{
com = new ComObject();
// Process COM objects here.
// Do NOT return out of this function yourself!
}
finally
{
// Release all COM objects.
System.Runtime.InteropServices.Marshal.ReleaseComObject(com);
// Set all COM objects to [null].
// The base class will take care of explicit garbage collection.
com = null;
}
return (result);
}
}
在单元测试中,我已经能够通过反射来验证以下内容:
上述内容很容易通过反思实现,但我正在努力宣称以下列表:
[return (result);]
行未被修改,并且未添加其他[return (whatever);]
个来电。不知道如何实现这一目标。我考虑过解析源代码,但除非绝对必要,否则我不喜欢这个解决方案。这是凌乱的,除非我有表达树,几乎不可能保证成功。
任何提示都将不胜感激。
答案 0 :(得分:6)
一些想法:
virtual
而不是abstract
?catch { throw; }
没用。删除它。void
方法返回布尔值会导致编译器错误。null
是没用的。IDisposable
。通常:您的大多数要求似乎没有商业价值。
catch
条款? 您应该考虑您的实际业务需求,并在其后对您的类进行建模。如果类需要履行某个合同,那么合同的模型。将实现保留给实现者。
关于提出的实际问题:
你不能在这里使用反射。您可以分析原始源代码或已编译程序集的IL代码
这两个选项都相当棘手,很可能无法在有限的时间内完成。我很肯定修复架构比实现其中一个选项花费的时间更少。
答案 1 :(得分:2)
如果完全自动化的代码分析是您真正需要的,那么您可以尝试使用Roslyn CTP。它具有比反射更高级的语法和语义分析。但它仍然是很多工作。直接与开发人员合作,而不是使用他们的代码,准备模板,指南可能会更加节省时间。
答案 2 :(得分:0)
虽然我确信你有充分的理由要求这样严格的要求......你是否考虑过将Lambda / Delegates / Action传递给Test函数?
无法解决所有问题,但更逻辑地会给你一些你想要的行为(例如,不能返回,不能有类级变量,不能在任何地方编写代码而是指定)。
最大的担忧是捕获变量......但可能会有解决方法。
示例代码:
//I'd make a few signatures....
bool OnTest<T1, T2> (Action<ComObject, T1, T2> logic, T1 first, T2 second)
{
bool result = false;
ComObject com = null;
//no checks needed re parameters
//Can add reflection tests here if wanted before code is run.
try
{
com = new ComObject();
//can't return
logic(com, first,second);
}
finally
{
// Release all COM objects.
System.Runtime.InteropServices.Marshal.ReleaseComObject(com);
// Set all COM objects to [null].
// The base class will take care of explicit garbage collection.
com = null;
//If you want, we can check each argument and if it is disposable dispose.
if (first is IDisposable && first != null) ((IDisposable) first).Dispose();
...
}
return (result); //can't be changed
}
不知道这是否有用,但这只是一个想法。哦,作为一个想法,它没有彻底或经过测试 - 我希望你能大幅度地发展它。