2

如果您需要测试另一个项目中的非公共属性,它会使用 Microsoft 单元测试向导创建 Accessor 对象。在我的单元测试中,我创建了辅助函数,这样我就不会在每个单元测试方法中重复相同的代码。目前我有两个几乎相同的测试,除了一个采用标准对象,另一个采用 Accessor 版本。由于访问器基于标准版本,我应该能够拥有一个功能,并且我认为我应该能够使用泛型来完成。问题是尝试重新输入和编译失败。

以下是现有的两个功能:

// 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();
}

我尝试将组合函数的签名更改为:

internal static void CreateAccount<T>(out T account, bool saveToDatabase) {...}

但无法将 T 正确地重铸为 Account 或 Account_Accessor。有什么建议么?

4

2 回答 2

3

由于这两种方法,您应该向泛型函数添加约束:

account.Notes = Utilities.RandomString(1000);
account.Create();

我建议您使用这两种方法添加一些接口,并将继承添加到您的两个类中。约束应该如下:

where T : YourNewInterface

关于约束,您可以在http://msdn.microsoft.com/en-us/library/bb384067.aspx上阅读

更新

public interface IAccount
    {
        string Notes { get; set; }
        void Create();
        void Init(DateTime created, string createdBy);
    }

public class Account : IAccount
{
    public string Notes
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void IAccount.Create()
    {
        throw new NotImplementedException();
    }

    void IAccount.Init(DateTime created, string createdBy)
    {
        throw new NotImplementedException();
    }
}

public class Account_Accessor : IAccount
{

    string IAccount.Notes
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void IAccount.Create()
    {
        throw new NotImplementedException();
    }

    void IAccount.Init(DateTime created, string createdBy)
    {
        throw new NotImplementedException();
    }
}


class Program
{
    internal static void CreateAccount<T>(out T account, bool saveToDatabase) where T : IAccount,new()
    {
        DateTime created = DateTime.Now;
        string createdBy = _testUserName;

        account = new T();
        account.Init(created, createdBy);

        account = (T)Activator.CreateInstance(typeof(T), new object[] { created, createdBy });

        account.Notes = Utilities.RandomString(1000);

        if (saveToDatabase)
            account.Create();
    }
    static void Main(string[] args)
    {
        Account acc;
        Account_Accessor acc2;
        CreateAccount(out acc, false);
        CreateAccount(out acc2, false);
    }
}

以下是关于我的示例的一些评论:
1. 我已CreateInstance通过添加new()约束来替换。
2. 由于.NET 泛型限制,new() 约束不能有参数,所以我Init()在接口中添加了方法IAccount
3.Init方法不应该被Account类的客户端代码调用,这就是为什么我们将方法定义为私有的,并明确地为IAccount。
4. 由于new()约束,您应该为Account. 如果您这样做,您的客户端代码不应调用此无参数 ctor。

至于我,我会Activator.CreateInstance原样离开。对于通用new()约束的限制,这是一个很好的解决方法

于 2012-10-21T15:00:22.323 回答
0

Here's my take on making that method generic.

public abstract class BaseAccount
{
    public string Notes;

    public virtual void Create() { ... }
}

public class Account : BaseAccount { ... }

public class Account_Accessor : BaseAccount { ... }

internal static void CreateAccount<T>(out T account, bool saveToDatabase) where T : BaseAccount
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = (T)Activator.CreateInstance(typeof(T), new object[] { created, createdBy });

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

I assume that Account and Account_Accessor are similar enough that they can share a similar class hiearchy, or could implement the same interface. In this example, I've provided an abstract class from which they both derive, but it is very easy to do it with an interface instead. However, the full implementation will have to be done in both class.

Knowing that, I can constraint the generic method so that T is only a child of BaseAccount. This way, I can access member from that base class without knowing the real type of T.

于 2012-10-21T16:01:55.317 回答