2012-10-24 1 views
2

다른 프로젝트의 비공개 속성을 테스트해야하는 경우 Microsoft 단위 테스트 마법사가 접근 자 개체를 만듭니다. 내 단위 테스트 내에서 모든 단위 테스트 메서드에서 동일한 코드를 반복하지 않도록 도우미 함수를 만듭니다. 현재 하나의 표준 공용 객체를 사용하고 다른 하나는 접근 자 버전을 사용한다는 것을 제외하고는 거의 동일한 두 가지 테스트가 있습니다. 액세서는 공용 객체를 기반으로하므로 하나의 기능을 가질 수 있어야합니다. 나는 간단한 캐스트로 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가 작성하는 액세스 용 코드입니다 (다시, 나는 예를 단순화하기 위해 아래로 감소) :

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("[email protected]")] 
     public Account_Accessor(DateTime created, string createdBy); 

     [Shadowing("_notes")] 
     public string _notes { get; set; } 

     public static Account_Accessor AttachShadow(object value); 

     [Shadowing("[email protected]")] 
     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("[email protected]")] 
     public void add_PropertyChanged(PropertyChangedEventHandler value); 
     public static ProjectBase_Accessor<T> AttachShadow(object value); 

     [Shadowing("[email protected]")] 
     public virtual void Create(); 
    } 
} 
+0

'Account'와'Account_Accessor'의 차이점은 무엇입니까? –

+0

내 대답을 무시하십시오. 그것은 분명히 당신의 다른 질문에서 나온 것과 같은 대답이었습니다. http://stackoverflow.com/a/12998986/2009. 다른 말로하면 제네릭은 사실 최소한의 양의 일로 제네릭을 수행 할 수있는 방법이라고 생각합니다. – hometoast

+0

@dthorpe가 가리키는 것처럼 Accessor가 BaseShadow를 상속받습니다 (기본 클래스를 거친 후). – Josh

답변

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

계정 인스턴스의 건설은, 그것도위한 공통 루틴을 가지고있는 공통 기능의 앞에 유형 특정 래퍼를 넣어 원하는만큼 복잡하다면 :

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()을 사용하여 그것을 끓여 버린다 할지라도, 누군가는 사용할 유형을 선택해야합니다.

일단 인스턴스가 구성되고 두 유형 모두 공통 인터페이스를 구현하면 모든 공통 기능에 공통 인터페이스가 중요합니다.

+0

감사합니다. 두 객체가 같은 소스에서 상속받지 않기 때문에 객체를 전달하고 Account 또는 Account_Accessor로 캐스팅 해보면 동일한 문제가 있다고 가정합니다. – Josh

+0

수정. 매개 변수 유형 Object를 만들 수 있지만 메서드 호출을하려면 해당 개체를 특정 유형 (Account 또는 Account_Accessor)으로 유형을 변환해야합니다. 두 가지 유형이 관련이 없으므로 공통 코드가 객체로 무언가를하고 싶을 때마다 if 문을 분기하거나 가지고 있어야한다는 것을 의미합니다. 아마도 문제의 가치가 없습니다. – dthorpe

+0

전위적인 가능성은 공통 루틴에서 동적 객체를 사용하려고 시도하는 것일 수 있습니다. 동적 객체는 JavaScript가 작동하는 방식과 비슷한 후기 바인딩 유형입니다. 이론적으로, 이는 객체에 대해 "foo"메소드를 찾는 것이 컴파일 타임에 발생하지 않는다는 것을 의미합니다. 즉, 런타임에 발생하기 때문에 어떤 객체 인스턴스가 관련되어 있는지에 관계없이 런타임에 동일한 이름의 메소드를 발견 할 수 있습니다. 필자는 구현 제안을 제공하기에 역학에 익숙하지 않지만 조사할만한 가치가있을 수 있습니다. – dthorpe

관련 문제