2017-11-29 13 views
0

테스트 할 메서드 내에서 서비스 호출을 모의하려고합니다.Moq 메서드를 사용한 단위 테스트가 Task.Run 내부에서 호출되었습니다.

는 메소드 본문은 다음과 같습니다

public string OnActionException(HttpActionContext httpRequest, Exception ex) 
{ 
    var formattedActionException = ActionLevelExceptionManager.GetActionExceptionMessage(httpRequest); 

    var mainErrorMessage = $"[{formattedActionException.ErrorId}]{formattedActionException.ErrorMessage}, {ex.Message}"; 

    this.LogError(mainErrorMessage, ex); 

    if (this._configuration.MailSupportOnException) 
     Task.Run(async() => await this._mailService.SendEmailForThrownException(this._configuration.SupportEmail, $"{mainErrorMessage} ---> Stack trace: {ex.StackTrace.ToString()}")); 

    return $"(ErrID:{formattedActionException.ErrorId}) {formattedActionException.ErrorMessage} {formattedActionException.KindMessage}"; 
} 

내가 내 테스트 내부 조롱하려고하는 것은 :

Task.Run (비동기() =이> 기다리고 this._mailService.SendEmailForThrownException (this._configuration.SupportEmail, $ "{mainErrorMessage} ---> 스택 추적 : {ex.StackTrace.ToString()}"));

시험 방법은 다음과 같습니다

[TestMethod] 
public void We_Send_System_Exception_On_Email_If_Configured_In_Settings() 
{ 
    // arrange 
    this._configurationWrapperMock.Setup(cwm => cwm.MailSupportOnException) 
     .Returns(true); 
    this._mailServiceMock.Setup(msm => msm.SendEmailForThrownException(It.IsAny<string>(), It.IsAny<string>())) 
     .Returns(Task.FromResult(0)); 

    // act 
    var logger = new ApiLogger(this._configurationWrapperMock.Object, this._mailServiceMock.Object); 
    logger.OnActionException(
     new HttpActionContext(
      new HttpControllerContext() 
      { 
       Request = new HttpRequestMessage() 
       { 
        Method = HttpMethod.Get, 
        RequestUri = new System.Uri("https://www.google.bg/") 
       } 
      }, 
      new ReflectedHttpActionDescriptor() { } 
     ), 
     new System.Exception()); 

    // assert 
    this._mailServiceMock.Verify(
     msm => msm.SendEmailForThrownException(It.IsAny<string>(), It.IsAny<string>()), 
     Times.Once); 
} 

문제는 내 어설 션이 실패 할 수 있도록 방법은 호출되지 않습니다 것입니다.

편집 : 내 질문을 변경할 수 있습니다. 어떻게 내 테스트 할 수 있도록 내 메서드를 다시 작성해야합니까?

+0

코드가 예상 경로를 통과하는지 테스트 디버깅을 시도 했습니까? –

+0

작업이 실행 중입니다. 다른 스레드에서 실행 중이므로 확인할 수 없습니다. – Nkosi

+0

@KerriBrown이 줄을 살펴 보았지만 디버깅을했지만 Moq가이를 감지하지 못했습니다. Moq은 결코 호출되지 않는다고 말했습니다. – user2128702

답변

0

위의 시나리오를 단순하게 축소하고 단위 테스트를 일관되게 통과 시키려고했습니다. (I는 꺾쇠 괄호를 사용할 수 없기 때문에 중괄호를 사용)하고 또한 단위 테스트 비동기을 당신이 작업 {문자열을} 반환 OnActionException 확인해야합니다 같은

public interface IService 
{ 
    Task<bool> Do(); 
} 

public class AsyncService : IService 
{ 
    public async Task<bool> Do() 
    { 
     return await Task.FromResult(true); 
    } 
} 

public class MyClass 
{ 
    private IService service; 

    public MyClass(IService service) 
    { 
     this.service = service; 
    } 

    public async Task<bool> Run() 
    { 
     return await this.service.Do(); 
    } 
} 

[TestMethod] 
public async Task TestAsyncMethod() 
{ 
    Mock<IService> mockService = new Mock<IService>(); 
    mockService.Setup(m => m.Do()).Returns(Task.FromResult(false)); 

    MyClass myClass = new MyClass(mockService.Object); 
    await myClass.Run(); 

    mockService.Verify(m => m.Do(), Times.Once); 
} 

는 것 같습니다. 따라서 Task.Run()을 사용하는 대신 OnActionException 메서드에서 this._mailService.SendEmailForThrownException()을 반환하면됩니다.

+0

답변을 수락합니다. 나는 그것을 시험해 보았고 그것이 효과가있을 것이라는 것을 안다. 현재 상황을 개선 할 수 있는지 궁금 해서요. – user2128702

1

제가 생각해 낸 해결책은 Sync라는 새로운 서비스 metod를 추출하는 것이 었습니다. 내부적으로 Thead.Run을 사용하여 별도의 스레드에서 비동기 메소드를 개인적으로 호출합니다.

public void ReportExceptionOnEmail(string recipient, string exceptionBody) 
{ 
    Task.Run(async() => await this.SendEmailForThrownException(recipient, exceptionBody)); 
} 

private async Task SendEmailForThrownException(string recipientEmail, string exceptionBody) 

그래서 지금은 장치가 문제없이 내 ReportExceptionOnEmail 방법을 테스트 할 수 있습니다.

0

코드는 Humble Object Pattern을 적용하는 고전적인 상황입니다.

[TestMethod] 
public void We_Send_System_Exception_On_Email_If_Configured_In_Settings() 
{ 
    ... 

    var logger = new Mock<ApiLogger>(MockBehavior.Default, 
            new object[] 
            { 
             this._configurationWrapperMock.Object, 
             this._mailServiceMock.Object 
            }).Object; 

    logger.OnActionException(...); 


    this._mailServiceMock.Verify(
      msm => msm.SendEmailForThrownException(It.IsAny<string>(), It.IsAny<string>()), 
      Times.Once); 
} 
: 그런 다음 테스트가 모양을

public class ApiLogger 
{ 
    ... 

    public string OnActionException(Exception ex) 
    { 
     ... 
     if (this._configuration.MailSupportOnException) 
      RunInTask(...); 
     ... 
    } 

    public virtual Task RunInTask(Action action) 
    { 
     return Task.Run(action); 
    } 
} 

:이 경우

은 당신이해야 할 모든 가상 방법으로, 다음 부분 모의 SUT의를 Task.Run를 추출하고이 가상 메소드를 오버라이드 (override)하는 것입니다