Moq: настроить универсальный метод с проверенными параметрами - PullRequest
0 голосов
/ 03 сентября 2018

Я пытался написать несколько тестов в NUnit для моих общих методов, но безуспешно. Я надеюсь, что смогу прояснить ситуацию, так как мне пришлось перефразировать мой код.

DoBusinessLogic () - это метод, который я хочу проверить. Он вызывает два других метода из базового класса:

public class MySvc : BaseSvc, IMySvc
{
    private readonly IMyRepo _repo;
    private readonly IMyConnectorClass _connector
    public MySvc(IMyRepo repo) : base(repo)        
    {
        _repo = repo;
        _connector = _repo.GetConnector();
    }

    public async Task DoBusinessLogic(int id1, int id2){
        bool doesFirstObjectExist = await CheckMainObjExists<Foo>(id1, _connector);
        await CheckSubObjExists<Bar>(id2, _connector);
        // further business logic
    }
}

Эти методы, в свою очередь, вызывают один и тот же метод репозитория, но имеют разную логику:

public abstract class BaseSvc : IBaseSvc
{
    private readonly IBaseRepo _repo
    protected BaseSvc(IBaseRepo repo)
    {
        _repo = repo;
    }

    protected async Task<bool> CheckMainObjExists<T>(int? id, IMyConnectorClass connector)
    {
        return await _repo.GetObjectByIdAsync<T>(Id, connector) != null;
    }

    protected async Task CheckSubObjExists<T>(int? id, IMyConnectorClass connector)
    {
        if (await _repo.GetObjectByIdAsync<T>(Id, connector) == null)
            { throw new Exception("Object not found!"); }
    }
}

Далее я хочу написать unit-тест для DoBusinessLogic () в классе MySvc. К сожалению, похоже, я не могу высмеять ответы из хранилища.

[TestFixture]
public class MySvcTests
{
    private MySvc _svc;
    private Mock<IMyRepo> _repoMock;
    private Mock<IMyConnectorClass> _connectorMock;

    [SetUp]
    public void SetUp()
    {
        _repoMock = new Mock<IMyRepo>() {};
        _connectorMock = new Mock<IMyConnectorClass>();

        _repo.SetUp(r => r.GetConnector()).Return(_connectorMock.Object);

        _svc = new MySvc(_repoMock);    
    }

    /* 
    My intent in this test, is to make CheckMainObjExists() pass,
    but make CheckSubObjExist() fail.
    */
    [Test]
    public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException()
    {
        // This should return an object
        _repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync(new Foo());

        // This should return null
        _repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync((Bar) null);

        Assert.Throws<Exception>(await _svc.DoBusinessLogic());
    }
}

Однако, когда я запускаю тест, оба метода, которые я настроил для своего фиктивного репо, возвращают ноль, в то время как я ожидаю "true" от первого. Я не знаю, где находится проблема, но у меня есть подозрения:

  1. Можно ли настроить метод, используя в качестве параметра макет объекта? В этом случае возможно ли использовать _connectorMock.Object в качестве параметра настройки?
  2. Можно ли настроить один и тот же универсальный метод несколько раз, но каждый раз для другого типа? Сначала это настройка для Foo, затем для Bar.

1 Ответ

0 голосов
/ 03 сентября 2018

Я только что проверил этот код, и он работает, как и ожидалось. Теперь мне пришлось сделать много предположений только для того, чтобы заставить код компилироваться и запускаться, что означало бы, что мой тест вашего кода некорректен, поскольку я мог исправить то, что было опущено в вашем примере.

Я не внес изменений в ваш код настройки теста, который сработал.

[TestClass]
public class MySvcTests {
    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException() {
        var _repoMock = new Mock<IMyRepo>() { };
        var _connectorMock = new Mock<IMyConnectorClass>();

        _repoMock.Setup(r => r.GetConnector()).Returns(_connectorMock.Object);

        var _svc = new MySvc(_repoMock.Object);
        // This should return an object
        _repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync(new Foo());

        // This should return null
        _repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync((Bar)null);

        await _svc.DoBusinessLogic(0, 0);
    }
}
...