如果需要测试其他项目的非公共属性,Microsoft单元测试向导会创建Accessor对象。在我的单元测试中,我创建了辅助函数,这样我就不会在每个单元测试方法中重复相同的代码。目前我有两个几乎相同的测试,除了一个采用标准公共对象,另一个采用Accessor版本。由于Accessor基于公共对象,因此我应该能够拥有一个功能。我曾经假设我可以使用Generics来完成一个简单的演员。但在posting the question之后我发现它还有很多工作要做,包括必须更新底层对象。我的问题是另一种方法是将这些冗余方法减少到只使用一个使用强制转换(或其他)方法的函数?
以下是现有的两个功能:
// Common function to create a new test record with standard Account object
internal static void CreateAccount(out Account account, bool saveToDatabase)
{
DateTime created = DateTime.Now;
string createdBy = _testUserName;
account = new Account(created, createdBy);
account.Notes = Utilities.RandomString(1000);
if (saveToDatabase)
account.Create();
}
// Common function to create a new test record with Account_Accessor
internal static void CreateAccount(out Account_Accessor account, bool saveToDatabase)
{
DateTime created = DateTime.Now;
string createdBy = _testUserName;
account = new Account_Accessor(created, createdBy);
account.Notes = Utilities.RandomString(1000);
if (saveToDatabase)
account.Create();
}
我有二十几个单元测试,真实对象平均有10个属性,我在这里简化了示例。
以下是单元测试API创建的Accessor代码(同样,我已将其缩减以简化示例):
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.ObjectModel;
using System.Data;
namespace NameHere.Bll
{
[Shadowing("NameHere.Bll.Account")]
public class Account_Accessor : ProjectBase_Accessor<Account>
{
protected static PrivateType m_privateType;
public Account_Accessor(PrivateObject value);
[Shadowing(".ctor@2")]
public Account_Accessor(DateTime created, string createdBy);
[Shadowing("_notes")]
public string _notes { get; set; }
public static Account_Accessor AttachShadow(object value);
[Shadowing("Create@0")]
public override void Create();
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace NameHere.Bll
{
[Shadowing("NameHere.Bll.ProjectBase`1")]
public class ProjectBase_Accessor<T> : BaseShadow, INotifyPropertyChanged
{
protected static PrivateType m_privateType;
public ProjectBase_Accessor(PrivateObject value);
[Shadowing("Created")]
public DateTime Created { get; set; }
public static PrivateType ShadowedType { get; }
[Shadowing("add_PropertyChanged@1")]
public void add_PropertyChanged(PropertyChangedEventHandler value);
public static ProjectBase_Accessor<T> AttachShadow(object value);
[Shadowing("Create@0")]
public virtual void Create();
}
}
答案 0 :(得分:3)
问题是即使访问者类暴露与它所影子的类相同的方法和属性,访问者和原始类之间也没有共同的接口。 Account_Accessor继承自BaseShadow,Account继承自其他东西。就编译器而言,它们是完全不相关的类型,而不是赋值兼容,因此很难将每个实例传递到公共例程中。
如果您可以强制Account_Accessor类实现也由Account实现的接口类型,则可以将每个实例传递给将接口类型作为参数的函数。像这样:
internal static IAccount SetupAccount(IAccount account, bool saveToDatabase)
{
// do account setup here - not construction
}
// to call: construct instance, then pass to common function
var account = new Account(a, b);
SetupAccount(account, true);
如果Account实例的构造足够复杂,您也希望有一个公共例程,请将特定于类型的包装器放在公共函数的前面:
internal static IAccount CreateAccount(bool saveToDatabase)
{
var account = new Account(a,b);
return SetupAccount(account, saveToDatabase);
}
internal static IAccount CreateAccountAccessor(bool saveToDatabase)
{
var account = new Account_Accessor(a,b);
return SetupAccount(account, saveToDatabase);
}
你无法逃避的一点是:某个地方的某个人必须承诺构建哪个实例。即使你把它归结为传递类型并使用Activator.CreateInstance()
,也有人必须承诺选择使用哪种类型。
一旦构造了实例,并且两种类型都实现了一个通用接口,那么需要关注的所有常见功能都是通用接口。