2

別のプロジェクトの非公開プロパティをテストする必要がある場合、Microsoft単体テストウィザードはAccessorオブジェクトを作成します。単体テスト内でヘルパー関数を作成して、すべての単体テストメソッドで同じコードを繰り返さないようにします。現在、1つは標準のパブリックオブジェクトを取得し、もう1つはAccessorバージョンを取得することを除いて、ほぼ同じ2つのテストがあります。アクセサーはパブリックオブジェクトに基づいているので、1つの関数を持つことができるはずです。私は、ジェネリックスを使用して単純なキャストで達成できると思っていました。しかし、質問を投稿した後、基になるオブジェクトを更新する必要があるなど、はるかに多くの作業が必要であることがわかりました。私の質問は、これらの冗長なメソッドを、キャスト(または別の)アプローチを使用して1つの関数のみを持つようにする別のアプローチですか?

既存の2つの関数は次のとおりです。

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

私はこれらの単体テストを20個持っており、実際のオブジェクトには平均10個のプロパティがあります。ここでは、例を簡略化しました。

ユニットテストAPIが作成するアクセサーコードは次のとおりです(ここでも、例を簡略化するために縮小しました)。

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

1 に答える 1

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

逃げられないポイントの1つは、これです。誰かが、どのインスタンスを構築するかをコミットする必要があります。タイプを渡して使用Activator.CreateInstance()することに要約しても、誰かが使用するタイプの選択にコミットする必要があります。

インスタンスが構築され、両方のタイプが共通のインターフェースを実装すると、注意する必要のあるすべての共通の関数は共通のインターフェースになります。

于 2012-10-24T17:48:12.037 に答える