Moq를 사용하여 C #에서 단위 테스트를 용이하게하는 방법

우리는 종종 데이터베이스 또는 파일 파일 시스템과 같은 외부 리소스에 액세스하는 코드에 대한 단위 테스트를 작성해야합니다. 이러한 리소스를 사용할 수없는 경우 테스트를 실행할 수 있는지 확인하는 유일한 방법은 모의 객체를 만드는 것입니다. 본질적으로 이러한 기본 종속성의 가짜 구현을 사용하여 테스트중인 메서드와 해당 종속성 간의 상호 작용을 테스트 할 수 있습니다. .Net 개발자에게 가장 널리 사용되는 모의 프레임 워크 중 세 가지는 Rhino Mocks, Moq 및 NMock입니다.

이 중에서 Moq는 가장 유연하고 사용하기 쉽습니다. Moq 프레임 워크는 모의를 설정, 테스트 및 검증하는 우아한 방법을 제공합니다. 이 기사에서는 Moq에 대한 설명과 Moq를 사용하여 종속성에서 코드 단위를 분리하는 방법을 설명합니다.

Moq 시작하기

Moq를 사용하여 실제 개체를 시뮬레이션하거나 모방하는 모의 개체를 만들 수 있습니다. Moq는 클래스와 인터페이스를 모두 모의하는 데 사용할 수 있습니다. 그러나 알아야 할 몇 가지 제한 사항이 있습니다. 모의 할 클래스는 정적이거나 봉인 될 수 없으며 모의되는 메서드는 가상으로 표시되어야합니다. (이러한 제한에 대한 해결 방법이 있습니다. 예를 들어 어댑터 디자인 패턴을 활용하여 정적 메서드를 모의 할 수 있습니다.)

Moq 사용의 첫 번째 단계는 단위 테스트 프로젝트에서 사용할 수 있도록 설치하는 것입니다. GitHub에서 Moq를 다운로드하고 적절하게 참조를 추가 할 수 있습니다. 그러나 NuGet을 통해 Moq를 설치하는 것이 더 쉽고 참조를 놓칠 가능성이 적기 때문에 선호합니다. NuGet 명령 줄에서 다음 명령을 사용하여 Moq를 설치할 수 있습니다.

Install-Package Moq

Moq를 사용하여 인터페이스를 모의하는 방법

인터페이스를 조롱하는 것으로 시작하겠습니다. Mock 클래스를 사용하여 모의 객체를 생성하는 구문은 다음과 같습니다.

모의 mockObjectType = new Mock ();

이제 IAuthor라는 다음 인터페이스를 고려하십시오.

공용 인터페이스 IAuthor

    {

        int Id {get; 세트; }

        string FirstName {get; 세트; }

        string LastName {get; 세트; }

    }

Moq 프레임 워크를 사용하여 모의 객체를 만들고, 속성 값을 설정하고, 매개 변수를 지정하고, 메서드 호출에서 값을 반환 할 수 있습니다. 다음 코드 스 니펫은 Moq를 사용하여 IAuthor 인터페이스에서 인스턴스를 만드는 방법을 보여줍니다.

var mock = new Mock ();

Mock 클래스는 Moq 프레임 워크에 속하며 만들려는 인터페이스 유형을 허용하는 일반 생성자를 포함합니다. Moq는 람다 식, 대리자 및 제네릭을 활용합니다. 이 모든 것이 프레임 워크 사용을 매우 직관적으로 만듭니다.

다음 코드 스 니펫은 IAuthor 인터페이스를 모의 처리하고 모의 된 인스턴스의 속성에 적절한 값을 제공하는 방법을 보여줍니다. Assert를 사용하여 모의 인스턴스의 속성 값을 확인하는 방법에 유의하십시오.

var author = new Mock ();

author.SetupGet (p => p.Id) .Returns (1);

author.SetupGet (p => p.FirstName) .Returns ( "Joydip");

author.SetupGet (p => p.LastName) .Returns (“Kanjilal”);

Assert.AreEqual ( "Joydip", author.Object.FirstName);

Assert.AreEqual ( "Kanjilal", author.Object.LastName);

Moq를 사용하여 방법을 모의하는 방법

이제 Article이라는 다음 클래스를 살펴 보겠습니다. Article 클래스에는 기사 ID를 매개 변수로 받아들이고 기사의 게시 날짜를 반환하는 GetPublicationDate라는 메서드가 하나만 포함되어 있습니다.

공개 클래스 기사

    {

        공개 가상 DateTime GetPublicationDate (int articleId)

        {

            새로운 NotImplementedException ();

        }

    }

GetPublicationDate 메서드는 Article 클래스에서 아직 구현되지 않았기 때문에 아래 제공된 코드 조각과 같이 현재 날짜를 게시 날짜로 반환하도록 메서드가 조롱되었습니다.

var mockObj = new Mock ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). Returns ((int x) => DateTime.Now);

Setup 메서드는 매개 변수로 전달되는 메서드의 동작을 정의하는 데 사용됩니다. 이 예제에서는 GetPublicationDate 메서드의 동작을 정의하는 데 사용됩니다. 에 대한 호출 It.IsAny()은 GetPublicationDate 메서드가 정수 유형의 매개 변수를 허용 함 을 의미합니다. It정적 클래스를 나타냅니다. Returns 메서드는 Setup 메서드 호출에 지정된 메서드의 반환 값을 지정하는 데 사용됩니다. 이 예제에서 Returns 메서드는 메서드의 반환 값을 현재 시스템 날짜로 지정하는 데 사용됩니다.

Moq를 사용하면 특정 메서드 또는 속성이 호출되었는지 확인할 수 있습니다. 다음 코드 스 니펫은이를 보여줍니다.

mockObj.Verify (t => t.GetPublicationDate (It.IsAny ()));

여기에서는 Verify 메서드를 사용하여 모의 개체에서 GetPublicationDate가 호출되었는지 확인합니다.

Moq를 사용하여 기본 클래스 메서드를 모의하는 방법

다음 코드를 고려하십시오. 여기에는 RepositoryBase 클래스와이를 확장하는 AuthorRepository 클래스의 두 가지 클래스가 있습니다.

공용 추상 클래스 RepositoryBase

{

    공개 가상 부울 IsServiceConnectionValid ()

    {

        // 일부 코드

    }

}

공용 클래스 AuthorRepository : RepositoryBase

{

    공개 무효 Save ()

    {

        if (IsServiceConnectionValid ())

        {

            // 일부 코드

        }

    }

}

이제 데이터베이스 연결이 유효한지 확인한다고 가정합니다. 그러나 IsServiceConnectionValid 메서드 내의 모든 코드를 테스트하고 싶지는 않을 수 있습니다. 예를 들어 IsServiceConnectionValid 메서드에는 타사 라이브러리와 관련된 코드가 포함될 수 있습니다. 우리는 그것을 테스트하고 싶지 않습니까? Moq의 CallBase 메서드가 구출되는 곳입니다. 

이와 같은 상황에서 모의 ​​유형으로 재정의 된 기본 클래스에 메서드가 있고 재정의 된 메서드의 기본 버전 만 모의해야하는 경우 CallBase에서 그릴 수 있습니다. 다음 코드 조각은 CallBase 속성을 true로 설정하여 AuthorRepository 클래스의 부분 모의 객체를 만드는 방법을 보여줍니다.

var mockObj = new Mock () {CallBase = true};

mockObj.Setup (x => x.IsServiceConnectionValid ()). Returns (true);

Moq 프레임 워크를 사용하면 필요한 기능만으로 테스트 용 클래스 및 인터페이스의 동작을 모방하는 모의 객체를 쉽게 만들 수 있습니다. 모의 테스트에 대한 자세한 내용은 Martin Fowler의이 훌륭한 기사를 확인하십시오.