Moq에서 메서드가 정확히 한 번 호출되었는지 어떻게 확인합니까?


112

Moq에서 메서드가 정확히 한 번 호출되었는지 어떻게 확인합니까? Verify()대의 Verifable()일이 정말 혼란.

답변:


165

Times.Once(), 또는 Times.Exactly(1)다음을 사용할 수 있습니다 .

mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));

Times 클래스 의 메서드는 다음과 같습니다 .

  • AtLeast -모의 메소드가 최소 횟수만큼 호출되어야 함을 지정합니다.
  • AtLeastOnce -모의 메소드가 최소 한 번 호출되도록 지정합니다.
  • AtMost -모의 메소드가 최대 시간에 호출되어야 함을 지정합니다.
  • AtMostOnce -모의 메소드가 최대 한 번 호출되도록 지정합니다.
  • Between -모의 메소드가 시작 시간과 종료 시간 사이에 호출되어야 함을 지정합니다.
  • Exactly -모의 메소드가 정확히 여러 번 호출되도록 지정합니다.
  • Never -모의 메소드가 호출되지 않도록 지정합니다.
  • Once -모의 메소드가 정확히 한 번 호출되도록 지정합니다.

메소드 호출이라는 것을 기억하십시오. 나는 그들이 속성이라고 생각하고 괄호를 잊어 버리고 계속 넘어졌습니다.


2
그래서 어떻게 mockContext를 얻거나 설정합니까?
Choco

2
@Choco 나는 그것이 그의 모의 인스턴스라고 가정합니다. 그래서 그것을 var mockContext = new Mock<IContext>()설정하는 것과 같은 것입니다.
Zack Huber

난 그냥 궁금 AtLeast, AtMost, Between, 또는 Exactly재산으로 볼 수 있습니다. 내 말은, obv는 무언가를하기 위해 매개 변수가 필요하다는 것입니다.
Danylo Yelizarov

8

정수 2 개를 더하는 한 가지 방법으로 계산기를 만들고 있다고 상상해보십시오. add 메서드가 호출 될 때 print 메서드를 한 번 호출해야한다는 요구 사항을 더 상상해 봅시다. 이를 테스트하는 방법은 다음과 같습니다.

public interface IPrinter
{
    void Print(int answer);
}

public class ConsolePrinter : IPrinter
{
    public void Print(int answer)
    {
        Console.WriteLine("The answer is {0}.", answer);
    }
}

public class Calculator
{
    private IPrinter printer;
    public Calculator(IPrinter printer)
    {
        this.printer = printer;
    }

    public void Add(int num1, int num2)
    {
        printer.Print(num1 + num2);
    }
}

다음은 추가 설명을 위해 코드 내에 주석이있는 실제 테스트입니다.

[TestClass]
public class CalculatorTests
{
    [TestMethod]
    public void WhenAddIsCalled__ItShouldCallPrint()
    {
        /* Arrange */
        var iPrinterMock = new Mock<IPrinter>();

        // Let's mock the method so when it is called, we handle it
        iPrinterMock.Setup(x => x.Print(It.IsAny<int>()));

        // Create the calculator and pass the mocked printer to it
        var calculator = new Calculator(iPrinterMock.Object);

        /* Act */
        calculator.Add(1, 1);

        /* Assert */
        // Let's make sure that the calculator's Add method called printer.Print. Here we are making sure it is called once but this is optional
        iPrinterMock.Verify(x => x.Print(It.IsAny<int>()), Times.Once);

        // Or we can be more specific and ensure that Print was called with the correct parameter.
        iPrinterMock.Verify(x => x.Print(3), Times.Once);
    }
}

참고 : 기본적으로 Moq는 Mock 개체를 만드는 즉시 모든 속성과 메서드를 스텁합니다. 따라서 호출하지 않아도 SetupMoq는 이미 메서드를 스텁 처리하여 IPrinter호출 할 수 있습니다 Verify. 그러나 특정 기대치를 충족하기 위해 메서드에 매개 변수를 적용하거나 특정 기대치 또는 호출 횟수를 충족하기 위해 메서드의 반환 값을 적용해야 할 수 있기 때문에 좋은 방법으로 항상 설정했습니다.


나는 부르고 Verify, Times.Once지금까지 호출하지 않고 Setup. 나는 Verify그 경우 확실히 폭발 할 것으로 예상 했지만 그렇지 않았다.
dudeNumber4

@ dudeNumber4 아니요, 기본적으로 Moq는 Mock개체 를 생성하자마자 모든 속성과 메서드를 스텁하기 때문에 폭발하지 않습니다 . 따라서 호출하지 않아도 SetupMoq는 이미 메서드를 스텁 처리하여 IPrinter호출 할 수 있습니다 Verify. 그러나 좋은 방법으로 메서드에 매개 변수를 적용하거나 메서드의 반환 값을 적용해야 할 수도 있으므로 항상 설정했습니다.
CodingYoshi

죄송합니다. 끔찍한 설명이었습니다. 나는라고 Times.Exactly(1)그것은 하지 않았다 방법은 실제로 두 번 호출 할 때 실패합니다. Setup문제의 메서드를 추가 한 후에 만 제대로 실패했습니다.
dudeNumber4

2

테스트 컨트롤러는 다음과 같습니다.

  public HttpResponseMessage DeleteCars(HttpRequestMessage request, int id)
    {
        Car item = _service.Get(id);
        if (item == null)
        {
            return request.CreateResponse(HttpStatusCode.NotFound);
        }

        _service.Remove(id);
        return request.CreateResponse(HttpStatusCode.OK);
    }

그리고 유효한 id로 DeleteCars 메서드를 호출하면이 테스트에 의해 정확히 한 번 호출 된 Service remove 메서드를 확인할 수 있습니다.

 [TestMethod]
    public void Delete_WhenInvokedWithValidId_ShouldBeCalledRevomeOnce()
    {
        //arange
        const int carid = 10;
        var car = new Car() { Id = carid, Year = 2001, Model = "TTT", Make = "CAR 1", Price=2000 };
        mockCarService.Setup(x => x.Get(It.IsAny<int>())).Returns(car);

        var httpRequestMessage = new HttpRequestMessage();
        httpRequestMessage.Properties[HttpPropertyKeys.HttpConfigurationKey] = new HttpConfiguration();

        //act
        var result = carController.DeleteCar(httpRequestMessage, vechileId);

        //assert
        mockCarService.Verify(x => x.Remove(carid), Times.Exactly(1));
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.