IT박스

인터페이스가없는 클래스를 어떻게 모의합니까?

itboxs 2021. 1. 7. 07:47
반응형

인터페이스가없는 클래스를 어떻게 모의합니까?


Windows 7에서 C #을 사용하여 .NET 4.0에서 작업하고 있습니다.

mock을 사용하여 일부 방법 간의 통신을 테스트하고 싶습니다. 유일한 문제는 인터페이스를 구현하지 않고하고 싶다는 것입니다. 가능합니까?

모의 객체에 대한 많은 주제와 튜토리얼을 읽었지만 모두 클래스가 아닌 인터페이스를 모의하는 데 사용되었습니다. Rhino와 Moq 프레임 워크를 사용해 보았습니다.


가짜가 필요한 모든 방법을 virtual비공개가 아닌 것으로 표시하기 만하면 됩니다. 그런 다음 메서드를 재정의 할 수있는 가짜를 만들 수 있습니다.

사용 new Mock<Type>하고 매개 변수가없는 생성자가없는 경우 매개 변수를 위의 호출 인수로 전달할 수 있습니다.param Objects


대부분의 모의 프레임 워크 (Moq 및 RhinoMocks 포함)는 모의 클래스를 대신하여 프록시 클래스를 생성하고 사용자가 정의한 동작으로 가상 메서드를 재정의합니다. 이로 인해 구체적 또는 추상 클래스의 인터페이스 또는 가상 메서드 만 모의 처리 할 수 ​​있습니다. 또한 구체적인 클래스를 모의하는 경우 모의 프레임 워크가 클래스를 인스턴스화하는 방법을 알 수 있도록 거의 항상 매개 변수없는 생성자를 제공해야합니다.

코드에서 인터페이스 생성을 싫어하는 이유는 무엇입니까?


MoQ를 사용하면 구체적인 클래스를 모의 할 수 있습니다.

var mocked = new Mock<MyConcreteClass>();

그러나이를 통해 virtual코드 (메서드 및 속성) 를 재정의 할 수 있습니다 .


표준 모의 프레임 워크는 프록시 클래스를 생성합니다. 이것이 기술적으로 인터페이스와 가상 방법으로 제한되는 이유입니다.

'일반적인'메서드도 모의하려면 프록시 생성 대신 계측과 함께 작동하는 도구가 필요합니다. 예를 들어 MS Moles와 Typemock이 그렇게 할 수 있습니다. 그러나 전자에는 끔찍한 'API'가 있고 후자는 상업적입니다.


그 클래스에 대한 인터페이스를 만드는 것이 더 낫다고 생각합니다. 그리고 인터페이스를 사용하여 단위 테스트를 만듭니다.

해당 클래스에 액세스 할 수없는 경우 해당 클래스에 대한 어댑터를 만들 수 있습니다.

예를 들면 :

public class RealClass
{
    int DoSomething(string input)
    {
        // real implementation here
    }
}

public interface IRealClassAdapter
{
    int DoSomething(string input);
}

public class RealClassAdapter : IRealClassAdapter
{
    readonly RealClass _realClass;

    public RealClassAdapter() => _realClass = new RealClass();

    int DoSomething(string input) => _realClass.DoSomething(input);
}

이렇게하면 IRealClassAdapter를 사용하여 클래스에 대한 모의 객체를 쉽게 만들 수 있습니다.

작동하기를 바랍니다.


테스트중인 클래스를 변경할 수없는 경우 제가 제안 할 수있는 유일한 옵션은 MS Fakes https://msdn.microsoft.com/en-us/library/hh549175.aspx를 사용하는 것 입니다. 그러나 MS Fakes는 Visual Studio의 일부 버전에서만 작동합니다.


더 나빠질 경우 인터페이스와 어댑터 쌍을 만들 수 있습니다. 대신 인터페이스를 사용하도록 ConcreteClass의 모든 사용을 변경하고 항상 프로덕션 코드에서 콘크리트 클래스 대신 어댑터를 전달합니다.

어댑터는 인터페이스를 구현하므로 모의 객체도 인터페이스를 구현할 수 있습니다.

메서드를 가상으로 만들거나 인터페이스를 추가하는 것보다 더 비계에 가깝지만 구체적인 클래스의 소스에 액세스 할 수없는 경우 바인딩에서 벗어날 수 있습니다.


I faced something like that in one of the old and legacy projects that i worked in that not contains any interfaces or best practice and also it's too hard to enforce them build things again or refactoring the code due to the maturity of the project business, So in my UnitTest project i used to create a Wrapper over the classes that I want to mock and that wrapper implement interface which contains all my needed methods that I want to setup and work with, Now I can mock the wrapper instead of the real class.

For Example:

Service you want to test which not contains virtual methods or implement interface

public class ServiceA{

public void A(){}

public String B(){}

}

Wrapper to moq

public class ServiceAWrapper : IServiceAWrapper{

public void A(){}

public String B(){}

}

The Wrapper Interface

public interface IServiceAWrapper{

void A();

String B();

}

In the unit test you can now mock the wrapper:

    public void A_Run_ChangeStateOfX()
    {
    var moq = new Mock<IServiceAWrapper>();
    moq.Setup(...);
    }

This might be not the best practice, but if your project rules force you in this way, do it. Also Put all your Wrappers inside your Unit Test project or Helper project specified only for the unit tests in order to not overload the project with unneeded wrappers or adaptors.

Update: This answer from more than a year but in this year i faced a lot of similar scenarios with different solutions. For example it's so easy to use Microsoft Fake Framework to create mocks, fakes and stubs and even test private and protected methods without any interfaces. You can read: https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017

ReferenceURL : https://stackoverflow.com/questions/20400734/how-do-i-mock-a-class-without-an-interface

반응형