2009-04-07 11 views
18

방금 ​​Moq로 전환하여 문제가 발생했습니다. 나는 비즈니스 객체의 새로운 인스턴스를 만들고, 사용자 입력 값으로부터 객체의 속성을 설정하고, 새로운 객체를 저장하기위한 메소드 (SaveCustomerContact)를 호출하는 메소드를 테스트하고있다. Business Object는 리모트 계층을 거치기 때.에 인수로 전달됩니다. SaveCustomerContact에 전달되는 객체가 예상대로 설정되는 모든 속성을 가지고 있는지 테스트해야합니다. 그러나 컨트롤러 메소드에서 새로운 것으로 인스턴스화되었으므로 그렇게 할 수 없습니다.Moq로 참조 매개 변수 값 확인

[TestMethod()] 
public void AddContactTest() { 

    int customerId = 0; 

    string name = "a"; 

    var actual = new CustomerContact(); 

    var expected = new CustomerContact() { 
     CustomerId = customerId, 
     Name = name 
    }; 

    model.Setup(m => m.CustomerId).Returns(customerId); 
    model.SetupProperty(m => model.CustomerContactName, name); 
    model.SetupProperty(m => m.PhoneNumber, string.Empty); 
    model.SetupProperty(m => m.FaxNumber, string.Empty); 
    model.SetupProperty(m => m.Email, string.Empty); 
    model.SetupProperty(m => m.ReceiveInvoiceFlag, false); 
    model.SetupProperty(m => m.ReceiveStatementFlag, false); 
    model.SetupProperty(m => m.ReceiveContractFlag, false); 
    model.SetupProperty(m => m.EmailFlag, false); 
    model.SetupProperty(m => m.FaxFlag, false); 
    model.SetupProperty(m => m.PostalMailFlag, false); 
    model.SetupProperty(m => m.CustomerLocationId, 0); 

    remote 
     .Setup(r => r.SaveCustomerContact(ref actual)) 
     .Callback(() => Assert.AreEqual(actual, expected)); 

    target.AddContact(); 

} 

이 그 매개 변수의 연락을 취하는 얻기 위해 많은 시도의 단지 가장 최근의 :

public void AddContact() { 

    var contact = new CustomerContact() { CustomerId = m_model.CustomerId }; 

    contact.Name = m_model.CustomerContactName; 
    contact.PhoneNumber = m_model.PhoneNumber; 
    contact.FaxNumber = m_model.FaxNumber; 
    contact.Email = m_model.Email; 
    contact.ReceiveInvoiceFlag = m_model.ReceiveInvoiceFlag; 
    contact.ReceiveStatementFlag = m_model.ReceiveStatementFlag; 
    contact.ReceiveContractFlag = m_model.ReceiveContractFlag; 
    contact.EmailFlag = m_model.EmailFlag; 
    contact.FaxFlag = m_model.FaxFlag; 
    contact.PostalMailFlag = m_model.PostalMailFlag; 
    contact.CustomerLocationId = m_model.CustomerLocationId; 

    RemotingHandler.SaveCustomerContact(ref contact); 
} 

여기 테스트입니다. 참고로 실제의 값은 초기 (구성된) 상태에서 변경되지 않습니다.

대상 호출이 실패한 후 Assert.AreEqual (expected, actual) 이동. .CallBack 대신 .Verifiable()을 추가 한 다음 대상 뒤에 remote.Verify를 호출하면 (또는 모의을 엄격하게 설정) 테스트에서 제공하는 매개 변수가 항상 실패하기 때문에 항상 실패합니다. 컨트롤러 메소드에서 작성된 인스턴스와 동일한 인스턴스.

저는 Moq 3.0.308.2를 사용하고 있습니다. 이것을 테스트하는 방법에 대한 아이디어는 인정 될 것입니다. 감사!

답변

19

정확한 해결책을 제공 할 수는 없지만 매개 변수를 값으로 받아서 RemotingHandler로 전달하는 어댑터 뒤에 pass-by-ref 의미 체계를 숨길 수 있습니다.이것은 (내가 :-) 심판 매개 변수를 항상 의심 오전) 조롱하기 쉬울 것, 인터페이스에서 "심판"사마귀를 제거 할

편집 : 당신이 모의 대신 스텁을 사용할 수

또는 예를 들어 :

public class StubRemotingHandler : IRemotingHandler 
{ 
    public CustomerContact savedContact; 

    public void SaveCustomerContact(ref CustomerContact contact) 
    { 
     savedContact = contact; 
    } 
} 

는 이제 시험에 저장된 객체를 검사 할 수 있습니다 :

IRemotingHandler remote = new StubRemotingHandler(); 
... 
//pass the stub to your object-under-test 
... 
target.AddContact(); 
Assert.AreEqual(expected, remote.savedContact); 

당신은 또한 당신의 의견에 말 :

, 내가 그래서 더 쉽게 테스트를 작성할 수있는 백엔드의 임의의 비트를 포장의 선례를 시작 싫어

난 그 정확히 사용자가 설정해야하는 선례 생각! 코드를 테스트 할 수없는 경우 테스트를 계속해야합니다. 테스트를 쉽게하고 보상 범위를 늘리십시오.

+0

나는이 글을 어떻게 스텁 시킬지 모르겠다. (스텁에 대해서는 잘 모르지만). 어떻게 처리 할 수 ​​있는지 자세히 설명해 주시겠습니까? –

+0

또한 ref 참조에 관해서는 동의하는 바가 있지만, 이는 리모팅 계층이 작동하는 방식이며, 테스트를 더 쉽게 작성할 수 있도록 백엔드의 임의 비트를 래핑하는 선례를 시작하는 것을 싫어합니다. –

+0

비슷한 문제가 있었는데 MoQ 작업을 할 때 너무 제로가되었습니다. 내 스텁을 쓸 수 있다는 것을 잊었습니다! 고맙습니다. –

9

불행히도 Moq의 직접적인 지원 없이는 이것이 가능하지 않을 수 있습니다. 문제는 람다식이 ref 나 out을 지원하지 않는다는 것입니다.

는 "A 람다 식을 직접 둘러싸는 방법에서 심판 또는 매개 변수에서을 캡처 할 수 없습니다."당신은 일을 같이

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

은 심지어 예를 얻을 수 없습니다. 설치 프로그램에 대한 참조 추가가 컴파일되지 않습니다.

당신은 더 http://groups.google.com/group/moqdisc

행운의 MOQ 토론을 체크 아웃 할 수 있습니다.

+0

대단한 답변입니다! :) – Delashmate

10

Moq의 최신 버전이이 시나리오를 지원합니다.

http://code.google.com/p/moq/wiki/QuickStart에서 빠른 시작에서 촬영 : 나는 유사한 문제가 발생했을

// ref arguments 
var instance = new Bar(); 
// Only matches if the ref argument to the invocation is the same instance 
mock.Setup(foo => foo.Submit(ref instance)).Returns(true); 
+6

응답 해 주셔서 감사합니다. 나는 이것을 퀵 스타트에서 보았습니다. 사실 저는 상사가 Moq의 최신 버전으로 업그레이드 할 것을 확신했습니다. 불행히도이 동작은 "호출에 대한 ref 인수가 같은 인스턴스 인 경우에만 일치합니다"라는 (매우 불분명하게) 제안 된 것을 따르지 않는 것처럼 보입니다. –

0

. 비트 내가 최신 Moq을 사용하여 같은 값을 전달하여 솔루션을 가지고

var instance = new Bar(); Mock.Setup (foo => foo.Submit (ref 인스턴스)) 반환 값 (true);

이전에도 동일한 방법을 사용하고 있었지만 실제로는 반환하지 않았습니다.

내부에서 실제 함수 인스턴스가 생성되고 단위 테스트 클래스에서 전달 된 인스턴스를 덮어 쓰면 문제가 발생했습니다. 나는 실제 클래스 내에서 인스턴스 생성을 제거한 다음 효과가 있었다.

희망이 있으면 도움이 될 것입니다.

감사합니다.