명시 적으로 지정하거나 오버로드를 사용하지 않고 서명에 선택적 인수가있는 메서드를 어떻게 Moq합니까?


119

다음 인터페이스가 제공됩니다.

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Moq를 사용하여 모의 시도 :

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

컴파일 시간에 다음 오류를 제공합니다.

표현식 트리는 선택적 인수를 사용하는 호출 또는 호출을 포함 할 수 없습니다.

위의 문제 가 Moq의 문제 목록에서 개선 된 것으로 제기되었으며 4.5 릴리스에 할당 된 것으로 보입니다 (그럴 때마다).

내 질문은 위의 내용이 곧 수정되지 않을 경우 어떻게해야합니까? 내가 모의 할 때마다 선택적 매개 변수의 기본값을 명시 적으로 설정하거나 (처음에 하나를 지정하는 점을 무너 뜨리는) 부울없이 오버로드를 생성하는 옵션 만 있습니까 (내가했던 것처럼 C # 4 이전)?

아니면이 문제를 극복하기 위해 더 현명한 방법을 찾은 사람이 있습니까?


5
두 번째 매개 변수에 It.IsAny <bool> ()을 지정하는 것이 합리적입니까?
Paul d' Aoust 2013-06-05

1 년 반 후에도 여전히 사실입니다.
Mukus 2014

@Mukus, PR을 떨어 뜨릴 수 있습니다.
IamDOM

답변:


91

현재 유일한 선택 bool은 설정에 매개 변수 를 명시 적으로 포함하는 것 입니다 Foo.

나는 그것이 기본값을 지정하는 목적을 훼손한다고 생각하지 않습니다. 기본값은 코드 호출의 편의성이지만 테스트에서 명시 적이어야한다고 생각합니다. bool매개 변수 지정을 생략 할 수 있습니다. 미래에, 누군가의 기본값 변경하면 어떻게됩니까 b에를 true? 이것은 실패한 테스트로 이어질 것입니다 (그리고 당연히 그렇습니다), 숨겨진 가정 때문에 수정하기가 더 어려울 것 b입니다 false. bool매개 변수를 명시 적으로 지정하면 테스트의 가독성이 향상된다는 또 다른 이점이 있습니다. 그것들을 살펴 보는 누군가 Foo는 두 개의 매개 변수를 받아들이는 하나의 함수가 있다는 것을 금방 알게 될 것입니다 . 그것은 적어도 내 2 센트입니다 :)

조롱 할 때마다 지정하는 것과 관련하여 코드를 복제하지 마십시오. 함수에서 모의 ​​객체를 생성 및 / 또는 초기화하여 단일 변경 지점 만 갖도록하십시오. 정말로 원한다면 Foo의 매개 변수를이 초기화 함수 에 복제하여 Moq의 명백한 단점을 극복 할 수 있습니다 .

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
    if(!b)
    {
        fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
    }
    else
    {
        ...
    }
}

1
훌륭한 답변입니다. 나는 이미 진행하여 내 모의에 명시 적으로 지정했지만 귀하의 답변은 내가 왜 이렇게 해야하는지 매우 명확하고 논리적 인 방식으로 확인합니다. 감사합니다, @Chris.
Appulus

9
기본 매개 변수를 변경하면 테스트를 중단해야합니다. 기본값이 변경 될 때 테스트가 실패하지 않는 것은 테스트가 잘못되었다는 신호일 수 있습니다. 코드는 기본값을 사용할 수 있지만 테스트는 사용하지 않습니까?
Pop Catalin 2013

오래되었지만 인터페이스 (Dapper의 IDConnection)를 모의하려고 할 때 Moq 에서이 접근 방식을 시도했지만 여전히 동일한 오류가 발생합니다. 이유는 무엇입니까? 샘플 라인 : mockDB.Setup (x => x.Query <MyObject> (It.IsAny <string> (), It.IsAny <DynamicParameters> (), It.IsAny <IDbTransaction> (), false, 600)). 반환 (새 목록 <MyObject> ()); 마지막 두 값은 내가 설정하는 방법의 선택적 매개 변수입니다.
Raelshark

4
Arrgggh! 무서운 if (!x) {} else {}안티 패턴 :
nicodemus13

1
@ nicodemus13 예,하지만 가능한 한 질문에서 OP의 예제에 가까운 코드 예제를 유지하려고했습니다. 나는 반드시 그것을지지 않을 것이다 :
크리스 맨틀

8

오늘이 문제가 발생하여 Moq는이 사용 사례를 지원하지 않습니다. 따라서이 경우 메서드를 재정의하는 것으로 충분할 것 같습니다.

public interface IFoo
{
    bool Foo(string a);

    bool Foo(string a, bool b);
}

이제 두 가지 방법을 모두 사용할 수 있으며이 예제는 작동합니다.

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

2

Moq 버전 4.10.1을 사용하여 다음을 수행 할 수있었습니다.

인터페이스 :

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

그리고 모의

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>(), It.IsAny<bool>())).Returns(false);

첫 번째 매개 변수가 okay 인 Foo에 대한 호출을 해결합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.