문제

공개 및 개인 방법이있는 수업 도서관을 구축하고 있습니다. 개인 방법을 테스트 할 수 있기를 원하지만 (대부분 개발 중에도 미래의 리팩토링에 유용 할 수도 있습니다).

이것을하는 올바른 방법은 무엇입니까?

도움이 되었습니까?

해결책

.NET을 사용하는 경우 사용해야합니다. InternalSvisibleToattribute.

다른 팁

개인 방법을 테스트하려면 무언가 잘못 될 수 있습니다. 단위 테스트는 (일반적으로 말하면) 클래스의 인터페이스를 테스트하기위한 것입니다. 이는 공개 (및 보호 된) 방법을 의미합니다. 물론 이에 대한 해결책을 "해킹"할 수는 있지만 (방법을 공개적으로 만들어도) 고려할 수도 있습니다.

  1. 테스트하려는 방법이 실제로 테스트 할 가치가있는 경우 자체 클래스로 옮길 가치가 있습니다.
  2. 개인 방법을 호출하는 공개 방법에 더 많은 테스트를 추가하여 개인 방법의 기능을 테스트합니다. (주석가가 지적했듯이, 이러한 개인 메소드의 기능이 실제로 공개 인터페이스의 일부인 경우에만이를 수행해야합니다. 실제로 사용자에게 숨겨진 기능 (예 : 단위 테스트)을 수행하는 경우 아마도 나쁘다).

개인 방법을 테스트하는 것은 유용하지 않을 수 있습니다. 그러나 때로는 테스트 방법에서 개인 방법을 호출하는 것을 좋아합니다. 테스트 데이터 생성에 대한 코드 복제를 방지하기 위해 대부분의 경우 ...

Microsoft는 다음과 같은 두 가지 메커니즘을 제공합니다.

접근자

  • 클래스 정의의 소스 코드를 얻었습니다
  • 클래스 이름을 마우스 오른쪽 버튼으로 클릭하십시오
  • "개인 액세서 만들기"를 선택하십시오.
  • 액세서가 생성 해야하는 프로젝트를 선택하십시오 => 당신은 foo_accessor라는 이름의 새 클래스로 끝납니다. 이 클래스는 편집 중에 동적으로 생성되며 모든 회원이 제공하는 모든 회원을 개인화합니다.

그러나 원래 클래스의 인터페이스의 변화와 관련하여 메커니즘은 때때로 약간 다루기 어려워집니다. 그래서 대부분의 시간은 이것을 사용하지 않습니다.

privateobject 클래스다른 방법은 Microsoft.visualstudio.testTools.Unittesting.privateObject를 사용하는 것입니다

// Wrap an already existing instance
PrivateObject accessor = new PrivateObject( objectInstanceToBeWrapped );

// Retrieve a private field
MyReturnType accessiblePrivateField = (MyReturnType) accessor.GetField( "privateFieldName" );

// Call a private method
accessor.Invoke( "PrivateMethodName", new Object[] {/* ... */} );

"외부 인터페이스 테스트에만 관심이 있어야합니다"철학에 동의하지 않습니다. 자동차 수리점은 바퀴가 회전하는지 확인하기 위해 테스트 만 있어야한다고 말하는 것과 비슷합니다. 그렇습니다. 궁극적으로 나는 외부 행동에 관심이 있지만 내 자신의 개인, 내부 테스트가 좀 더 구체적이고 요점에 대한 것을 좋아합니다. 예, 리팩터를 리팩터링하면 일부 테스트를 변경해야 할 수도 있지만, 대규모 리팩터가 아니라면 몇 가지만 변경해야하며 다른 (변경되지 않은) 내부 테스트가 여전히 작동한다는 사실 만 변경하면됩니다. 리팩토링이 성공했습니다.

공개 인터페이스 만 사용하여 모든 내부 사례를 다룰 수 있으며 이론적으로 모든 내부 방법 (또는 최소한 중요한 방법)을 공개 인터페이스를 사용하여 완전히 테스트 할 수 있지만 머리에 서서 달성해야 할 수도 있습니다. 이것은 공개 인터페이스를 통해 실행되는 테스트 사례와 테스트를 위해 설계된 솔루션의 내부 부분 사이의 연결은 식별하기가 어렵거나 불가능할 수 있습니다. 지적한 결과, 내부 기계가 제대로 작동하고 있음을 보장하는 개별 테스트는 리팩토링과 관련하여 사소한 테스트 변경의 가치가 있습니다. 적어도 그것은 내 경험이었습니다. 모든 리팩토링에 대해 테스트를 크게 변경해야한다면 아마도 이것이 의미가 없지만이 경우 디자인을 완전히 다시 생각해야 할 수도 있습니다. 좋은 디자인은 대규모 재 설계없이 대부분의 변화를 허용 할 수있을 정도로 유연해야합니다.

드문 경우 개인 기능을 테스트하고 싶었고 일반적으로 대신 보호되도록 수정했으며 공개 래퍼 기능으로 하위 클래스를 작성했습니다.

클래스:

...

protected void APrivateFunction()
{
    ...
}

...

테스트를위한 서브 클래스 :

...

[Test]
public void TestAPrivateFunction()
{
    APrivateFunction();
    //or whatever testing code you want here
}

...

더 근본적인 질문은 왜 개인 방법을 처음부터 테스트하려고하는지에 대한 질문입니다. 이는 해당 클래스의 공개 인터페이스를 통해 개인 메소드를 테스트하려는 코드 냄새이지만 해당 방법은 구현 세부 사항이므로 사유입니다. 공개 인터페이스의 동작에 대해서만 표지 아래에서 구현되는 방식에 대해서만 관심이 있어야합니다.

개인 메소드의 동작을 테스트하려면 공통 리팩토링을 사용하여 코드를 다른 클래스로 추출 할 수 있습니다 (패키지 레벨 가시성이 있으므로 공개 API의 일부가 아님). 그런 다음 그 행동을 분리하여 테스트 할 수 있습니다.

리팩토링의 산물은 개인 방법이 이제 원래 클래스의 공동 작업자가 된 별도의 클래스임을 의미합니다. 그 행동은 자체 단위 테스트를 통해 잘 이해되었을 것입니다.

그런 다음 원래 클래스를 테스트하려고 할 때 행동을 조롱 할 수 있으므로 대중 인터페이스의 조합 폭발과 모든 개인 방법의 동작을 테스트하지 않고 해당 클래스의 공개 인터페이스의 동작을 테스트하는 데 집중할 수 있습니다. .

나는 이것이 차를 운전하는 것과 유사하다는 것을 본다. 차를 운전할 때 보닛을 사용하여 운전하지 않아 엔진이 작동하는 것을 알 수 있습니다. 나는 자동차가 제공하는 인터페이스, 즉 엔진이 작동하고 있음을 알기 위해 REV 카운터와 속도계에 의존합니다. 나는 가스 페달을 눌렀을 때 차가 실제로 움직이는다는 사실에 의존합니다. 엔진을 테스트하고 싶다면 분리하여 확인할 수 있습니다. :디

물론 레거시 애플리케이션이있는 경우 개인 방법을 직접 테스트하는 것은 최후의 수단 일 수 있지만 레거시 코드가 더 나은 테스트를 가능하게하기 위해 리팩토링되는 것을 선호합니다. Michael Feathers는이 주제에 대해 훌륭한 책을 썼습니다. http://www.amazon.co.uk/working-effectally-legacy-robert-martin/dp/0131177052

개인 유형, 내부 및 개인 회원은 어떤 이유 때문에, 종종 직접 엉망이되고 싶지 않습니다. 그리고 만약 당신이 그렇게한다면, 그 집회를 만든 사람들이 개인/내부 구현을 유지한다는 보장은 없기 때문에 나중에 휴식을 취할 가능성이 있습니다.

그러나 때때로, 컴파일 된 또는 제 3 자 조립회의 해킹/탐색을 할 때, 나는 개인 또는 내부 생성자로 개인 클래스 또는 클래스를 초기화하기를 원했습니다. 또는 때로는 변경할 수없는 미리 컴파일 된 레거시 라이브러리를 다룰 때 개인 방법에 대한 테스트를 작성하게됩니다.

따라서 AccessPrivateWrapper에서 태어났습니다. http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html -C# 4.0 동적 기능과 반사를 사용하여 작업을 쉽게 만드는 빠른 래퍼 클래스입니다.

내부/개인 유형을 만들 수 있습니다

    //Note that the wrapper is dynamic
    dynamic wrapper = AccessPrivateWrapper.FromType
        (typeof(SomeKnownClass).Assembly,"ClassWithPrivateConstructor");

    //Access the private members
    wrapper.PrivateMethodInPrivateClass();

두 가지 방법으로 개인 방법을 테스트 할 수 있습니다.

  1. 인스턴스를 만들 수 있습니다 PrivateObject 클래스 구문은 다음과 같습니다

    PrivateObject obj= new PrivateObject(PrivateClass);
    //now with this obj you can call the private method of PrivateCalss.
    obj.PrivateMethod("Parameters");
    
  2. 반사를 사용할 수 있습니다.

    PrivateClass obj = new PrivateClass(); // Class containing private obj
    Type t = typeof(PrivateClass); 
    var x = t.InvokeMember("PrivateFunc", 
        BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public |  
            BindingFlags.Instance, null, obj, new object[] { 5 });
    

또한 InternalSvisibleToattribute 메소드를 사용했습니다. 이를 달성하기 위해 이전의 개인 방법을 내부에 내부적으로 만드는 것이 불편하다고 느끼면 어쨌든 직접 단위 테스트의 대상이되어서는 안된다고 언급 할 가치가 있습니다.

결국, 당신은 테스트하고 있습니다 행동 당신의 수업의 것보다는 특정 구현 - 전자를 변경하지 않고 후자를 변경할 수 있으며 테스트는 여전히 통과해야합니다.

개인 방법에는 두 가지 유형이 있습니다. 정적 개인 방법 및 비 정적 개인 방법 (인스턴스 방법). 다음 두 기사는 예제로 개인 방법을 테스트하는 방법을 설명합니다.

  1. 단위 테스트 정적 개인 방법
  2. 단위 테스트 비 정적 개인 방법

MS Test는 VScodeGenAccessors라는 파일을 만들어 프로젝트에서 개인 멤버와 메소드를 사용할 수 있도록하는 멋진 기능이 있습니다.

[System.Diagnostics.DebuggerStepThrough()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
    internal class BaseAccessor
    {

        protected Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject m_privateObject;

        protected BaseAccessor(object target, Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
        {
            m_privateObject = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target, type);
        }

        protected BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
            :
                this(null, type)
        {
        }

        internal virtual object Target
        {
            get
            {
                return m_privateObject.Target;
            }
        }

        public override string ToString()
        {
            return this.Target.ToString();
        }

        public override bool Equals(object obj)
        {
            if (typeof(BaseAccessor).IsInstanceOfType(obj))
            {
                obj = ((BaseAccessor)(obj)).Target;
            }
            return this.Target.Equals(obj);
        }

        public override int GetHashCode()
        {
            return this.Target.GetHashCode();
        }
    }

Baseaccessor에서 파생되는 수업이 있습니다

~와 같은

[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class SomeClassAccessor : BaseAccessor
{

    protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::Namespace.SomeClass));

    internal SomeClassAccessor(global::Namespace.Someclass target)
        : base(target, m_privateType)
    {
    }

    internal static string STATIC_STRING
    {
        get
        {
            string ret = ((string)(m_privateType.GetStaticField("STATIC_STRING")));
            return ret;
        }
        set
        {
            m_privateType.SetStaticField("STATIC_STRING", value);
        }
    }

    internal int memberVar    {
        get
        {
            int ret = ((int)(m_privateObject.GetField("memberVar")));
            return ret;
        }
        set
        {
            m_privateObject.SetField("memberVar", value);
        }
    }

    internal int PrivateMethodName(int paramName)
    {
        object[] args = new object[] {
            paramName};
        int ret = (int)(m_privateObject.Invoke("PrivateMethodName", new System.Type[] {
                typeof(int)}, args)));
        return ret;
    }

CodeProject에는 개인 방법 테스트의 장단점을 간략하게 논의하는 기사가 있습니다. 그런 다음 개인 메소드에 액세스하기위한 일부 반사 코드를 제공합니다 (Marcus가 위에서 제공하는 코드와 유사합니다.) 샘플에서 찾은 유일한 문제는 코드가 과부하 된 메소드를 고려하지 않는다는 것입니다.

여기에서 기사를 찾을 수 있습니다.

http://www.codeproject.com/kb/cs/testnonpublicmembers.aspx

그들을 선언하십시오 internal, 다음을 사용합니다 InternalsVisibleToAttribute 단위 테스트 어셈블리가이를 볼 수 있도록합니다.

컴파일러 지시문을 빠르게 혼란시키기 때문에 컴파일러 지시를 사용하지 않는 경향이 있습니다. 실제로 필요한 경우 완화하는 한 가지 방법은 부분 클래스에 넣고 제작 버전을 만들 때 빌드가 .CS 파일을 무시하게하는 것입니다.

처음에 코드의 개인 메소드를 테스트해서는 안됩니다. 수업의 '공개 인터페이스'또는 API를 테스트해야합니다. API는 외부 발신자에게 노출되는 모든 공개 방법입니다.

그 이유는 일단 수업의 개인 방법과 내부를 테스트하기 시작하면 클래스 (개인 사물)의 구현을 테스트에 연결하기 때문입니다. 즉, 구현 세부 정보를 변경하기로 결정하면 테스트도 변경해야합니다.

이런 이유로 InternalSvisibletoatrberbe를 사용하지 않아야합니다.

다음은이 주제를 다루는 Ian Cooper의 훌륭한 대화입니다. Ian Cooper : TDD, 어디서 잘못 되었습니까?

때로는 개인 선언을 테스트하는 것이 좋습니다. 기본적으로 컴파일러에는 하나의 공개 메소드가 있습니다 : Compile (String outputFilename, params string [] sourcesFilenames). 각 "숨겨진"선언을 테스트하지 않고 그러한 방법을 테스트하기가 어려울 것이라고 확신합니다!

그렇기 때문에 시각적 t#: 더 쉬운 테스트를 만들기 위해 만들었습니다. 무료 .NET 프로그래밍 언어 (C# v2.0 호환)입니다.

우리는 '.-'연산자를 추가했습니다. 그것은 단지 '.'처럼 행동합니다. 테스트 된 프로젝트에서 아무것도 변경하지 않고 테스트에서 숨겨진 선언에 액세스 할 수있는 경우를 제외하고 운영자.

당사 웹 사이트를 살펴보십시오. 다운로드 그것 무료로.

나는 아직 아무도 이것을 말하지 않았다는 사실에 놀랐지 만, 내가 사용한 해결책은 수업 내에서 정적 방법을 만들어 스스로 테스트하는 것입니다. 이를 통해 공개 및 사적으로 테스트 할 모든 것에 액세스 할 수 있습니다.

또한 스크립팅 언어 (Python, Ruby 및 PHP와 같은 OO 능력 포함)에서 실행될 때 파일 테스트 자체를 만들 수 있습니다. 당신의 변화가 아무것도 깨지지 않았는지 확인하는 좋은 방법. 이것은 분명히 모든 클래스를 테스트 할 수있는 확장 가능한 솔루션을 만듭니다. (항상 테스트를 실행하는 무효 메인으로 다른 언어로도 할 수 있습니다).

개인 방법을 테스트하려는 클래스에서 사용할 수있는 명확한 코드 예제를 작성하고 싶습니다.

테스트 사례 클래스에서는 이러한 방법을 포함시킨 다음 표시된대로 사용하십시오.

  /**
   *
   * @var Class_name_of_class_you_want_to_test_private_methods_in
   * note: the actual class and the private variable to store the 
   * class instance in, should at least be different case so that
   * they do not get confused in the code.  Here the class name is
   * is upper case while the private instance variable is all lower
   * case
   */
  private $class_name_of_class_you_want_to_test_private_methods_in;

  /**
   * This uses reflection to be able to get private methods to test
   * @param $methodName
   * @return ReflectionMethod
   */
  protected static function getMethod($methodName) {
    $class = new ReflectionClass('Class_name_of_class_you_want_to_test_private_methods_in');
    $method = $class->getMethod($methodName);
    $method->setAccessible(true);
    return $method;
  }

  /**
   * Uses reflection class to call private methods and get return values.
   * @param $methodName
   * @param array $params
   * @return mixed
   *
   * usage:     $this->_callMethod('_someFunctionName', array(param1,param2,param3));
   *  {params are in
   *   order in which they appear in the function declaration}
   */
  protected function _callMethod($methodName, $params=array()) {
    $method = self::getMethod($methodName);
    return $method->invokeArgs($this->class_name_of_class_you_want_to_test_private_methods_in, $params);
  }

$ this-> _ CallMethod ( '_ yodfunctionName', Array (param1, param2, param3));

원래 개인 기능에 표시되는 순서대로 매개 변수를 발행합니다.

모든 페스와 혼란없이 개인 방법을 실행하려는 사람이라면 누구나. 이것은 좋은 오래된 반사 만 사용하여 모든 단위 테스트 프레임 워크와 함께 작동합니다.

public class ReflectionTools
{
    // If the class is non-static
    public static Object InvokePrivate(Object objectUnderTest, string method, params object[] args)
    {
        Type t = objectUnderTest.GetType();
        return t.InvokeMember(method,
            BindingFlags.InvokeMethod |
            BindingFlags.NonPublic |
            BindingFlags.Instance |
            BindingFlags.Static,
            null,
            objectUnderTest,
            args);
    }
    // if the class is static
    public static Object InvokePrivate(Type typeOfObjectUnderTest, string method, params object[] args)
    {
        MemberInfo[] members = typeOfObjectUnderTest.GetMembers(BindingFlags.NonPublic | BindingFlags.Static);
        foreach(var member in members)
        {
            if (member.Name == method)
            {
                return typeOfObjectUnderTest.InvokeMember(method, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, typeOfObjectUnderTest, args);
            }
        }
        return null;
    }
}

그런 다음 실제 테스트에서 다음과 같은 작업을 수행 할 수 있습니다.

Assert.AreEqual( 
  ReflectionTools.InvokePrivate(
    typeof(StaticClassOfMethod), 
    "PrivateMethod"), 
  "Expected Result");

Assert.AreEqual( 
  ReflectionTools.InvokePrivate(
    new ClassOfMethod(), 
    "PrivateMethod"), 
  "Expected Result");

Mbunit은 반사기라는 멋진 래퍼를 얻었습니다.

Reflector dogReflector = new Reflector(new Dog());
dogReflector.Invoke("DreamAbout", DogDream.Food);

속성에서 값을 설정하고 얻을 수도 있습니다

dogReflector.GetProperty("Age");

"Test Private"에 관해서는 완벽한 세상에서 동의합니다. 개인 단위 테스트를 수행 할 필요는 없습니다. 그러나 실제 세계에서는 리팩토링 코드 대신 개인 테스트를 작성하고 싶을 수도 있습니다.

여기 좋은 일입니다 기사 개인 방법의 단위 테스트에 대해. 그러나 응용 프로그램이 테스트를 위해 특별히 설계 (테스트 전용 테스트 만 생성하는 것과 같은) 또는 테스트를위한 반사를 사용하도록하는 것이 더 나은지 잘 모르겠습니다. 우리 대부분은 두 번째 방법을 선택할 것입니다.

나는 사용한다 privateObject 수업. 그러나 비공개 방법을 테스트하지 않기 위해 앞에서 언급했듯이.

Class target = new Class();
PrivateObject obj = new PrivateObject(target);
var retVal = obj.Invoke("PrivateMethod");
Assert.AreEqual(retVal);
CC -Dprivate=public

"CC"는 내가 사용하는 시스템의 명령 줄 컴파일러입니다. -Dfoo=bar 동등합니다 #define foo bar. 따라서이 편집 옵션은 모든 개인 물건을 공개적으로 효과적으로 변경합니다.

다음은 먼저 메소드 서명을 예로 들었습니다.

private string[] SplitInternal()
{
    return Regex.Matches(Format, @"([^/\[\]]|\[[^]]*\])+")
                        .Cast<Match>()
                        .Select(m => m.Value)
                        .Where(s => !string.IsNullOrEmpty(s))
                        .ToArray();
}

테스트는 다음과 같습니다.

/// <summary>
///A test for SplitInternal
///</summary>
[TestMethod()]
[DeploymentItem("Git XmlLib vs2008.dll")]
public void SplitInternalTest()
{
    string path = "pair[path/to/@Key={0}]/Items/Item[Name={1}]/Date";
    object[] values = new object[] { 2, "Martin" };
    XPathString xp = new XPathString(path, values);

    PrivateObject param0 = new PrivateObject(xp);
    XPathString_Accessor target = new XPathString_Accessor(param0);
    string[] expected = new string[] {
        "pair[path/to/@Key={0}]",
        "Items",
        "Item[Name={1}]",
        "Date"
    };
    string[] actual;
    actual = target.SplitInternal();
    CollectionAssert.AreEqual(expected, actual);
}

이를 수행하는 방법은 방법을 갖는 것입니다. protected 그리고 테스트 할 수업을 상속하는 테스트 고정물을 작성하십시오. 이런 식으로, 당신은 당신의 방법을 돌리고 있습니다 public, 그러나 테스트를 활성화합니다.

1) 레거시 코드가있는 경우 개인 메소드를 테스트하는 유일한 방법은 반영입니다.

2) 새 코드 인 경우 다음 옵션이 있습니다.

  • 반사 사용 (복잡한)
  • 동일한 클래스에서 단위 테스트를 작성합니다 (테스트 코드를 사용하여 프로덕션 코드를 추악하게 만듭니다)
  • refactor 및 방법을 어떤 종류의 Util 클래스에서 공개하십시오.
  • @Visiblefortesting 주석을 사용하고 개인을 제거하십시오

나는 가장 단순하고 가장 복잡한 주석 방법을 선호합니다. 유일한 문제는 우리가 큰 관심사가 아니라고 생각하는 가시성을 높였다는 것입니다. 우리는 항상 인터페이스로 코딩해야하므로 인터페이스 MyService와 구현 MyServiceImpl이 있으면 MyServiceTest (테스트 인터페이스 메소드) 및 MyServiceImplTest (Test Private Method) 인 해당 테스트 클래스를 가질 수 있습니다. 모든 클라이언트는 어쨌든 인터페이스를 사용해야하므로 개인 방법의 가시성이 증가하더라도 실제로 중요하지 않아야합니다.

디버그 모드를 구축하는 동안 공개 또는 내부 (InternalSvisibleToattribute 포함)로 선언 할 수도 있습니다.

    /// <summary>
    /// This Method is private.
    /// </summary>
#if DEBUG
    public
#else
    private
#endif
    static string MyPrivateMethod()
    {
        return "false";
    }

코드가 부풀어 오르지 만 가능합니다 private 릴리스 빌드에서.

제 생각에는 Classe의 공개 API를 테스트해야합니다.

방법을 공개하고, 테스트를 단위 테스트하기 위해, 캡슐화가 구현 세부 정보를 드러내는 것을 깨뜨립니다.

좋은 공개 API는 클라이언트 코드의 즉각적인 목표를 해결하고 해당 목표를 완전히 해결합니다.

Visual Studio 2008에서 개인 메소드에 대한 테스트 방법을 생성 할 수 있습니다. 개인 메소드에 대한 단위 테스트를 만들 때 테스트 참조 폴더가 테스트 프로젝트에 추가되고 액세서가 해당 폴더에 추가됩니다. 액세서는 단위 테스트 방법의 논리에도 언급됩니다. 이 액세서를 사용하면 장치 테스트가 테스트중인 코드에서 개인 메소드를 호출 할 수 있습니다. 자세한 내용은 살펴보십시오

http://msdn.microsoft.com/en-us/library/bb385974.aspx

또한 InternalSvisibleToatrricber는 귀하의 조립이 필요합니다. 강한 이름, 이전에 해당 요구 사항이 없었던 솔루션에서 작업하는 경우 자체 문제 세트를 만듭니다. 액세서를 사용하여 개인 방법을 테스트합니다. 보다 이 질문 이것의 예를 위해서.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top