Брошенное исключение не обнаружено в UnitTest try / catch - PullRequest
0 голосов
/ 04 июля 2018

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

Вот клиент, которым я пользуюсь.

public class PipeClient : IPipeClient
{
    public async void Send(string host, string pipeName, Message msg)
    {
        if (string.IsNullOrEmpty(msg.PreparedMessage))
            throw new ArgumentException("MESSAGE_NOT_FOUND");

        if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(pipeName))
            throw new ArgumentNullException();

        if (!host.TryParseHost()) 
            throw new ArgumentException("INVALID_HOST_NAME");

        using (var pipeClient = new NamedPipeClientStream(host, pipeName, PipeDirection.Out))
        {
            pipeClient.Connect(200);

            using (var writer = new StreamWriter(pipeClient))
            {
                await Task.Run(() => writer.WriteLine(msg.PreparedMessage));
                writer.Flush();
            }
        }
    }
}

А вот UnitTest

    [TestMethod]
    public void Send_FailsOnWrongHostName()
    {
        var name = "FailWithHostname";
        var msg = new Message(MyStates.Register, "UnitTest", "Test");

        try
        {
            var client = new PipeClient();
            client.Send("lol", name, msg);
        }
        catch (Exception e)
        {
            Assert.IsTrue(e is ArgumentException);
        }
    }

Поэтому, когда я запускаю этот тест, он должен, насколько мне известно, генерировать исключение, когда я вызываю метод Send (который делает), а затем попадать в предложение catch, потому что я не перехватываю его внутри PipeClient. Тем не менее, это не так, он просто выходит с неудачным тестом.

Если вам нужна дополнительная информация, просто дайте мне знать, заранее спасибо.

1 Ответ

0 голосов
/ 04 июля 2018

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

Сначала краткая заметка об асинхронных методах и задачах.

  • Следует избегать асинхронной пустоты, кроме как в обработчике асинхронных событий. Асинхронные методы должны возвращать Task или Task, в противном случае вызывающему методу нечего удерживать, чтобы знать, когда метод завершен, и сообщать, вызвал ли метод исключение. Асинхронная пустота - это, по сути, огонь, и забудьте, что некому наблюдать за исключениями.

«В наблюдаемых заданиях никто не может кричать» -Ме, 2018

  • Исключения, генерируемые в асинхронных методах, красиво разворачиваются и выбрасываются когда ожидается асинхронный метод, со стеком вызовов все сохраняется и достаточно разумно. Если вы не ожидаете результата в конце концов в в какой-то момент в будущем вы получите исключение UnobservedTaskException это, если вы не настроили глобальный обработчик для, приведет к ваше приложение. Если вы получите результат асинхронного метода синхронно с помощью .Wait () или .Result или через .GetAwaiter (). GetResult () (все 3, которых следует избегать, кроме 3-го вариант лучше, если вам нужно, чтобы я был проинформирован), тогда вы будете получить исходное исключение, заключенное в AggregateException.

Теперь, если ничего из этого не имеет для вас особого смысла, я бы порекомендовал сделать несколько задач по чтению и выполнить асинхронное / ожидание.

Теперь на вашем тесте.

Ваш метод является асинхронным void, поэтому вызывающему методу ничего не нужно возвращать в него, чтобы представить работу или сообщить ему, что метод вызвал исключение. Итак, он продолжается, тест завершается, а затем все завершается без исключений, потому что UnobservedTaskException может быть выброшено в любой момент в будущем (я думаю, это связано с тем, когда сборщик мусора приводит в порядок ошибочную задачу, а затем выдает и потому, что мусор коллектор недетерминирован, мы не можем сказать, когда это произойдет)

Так что, если вы заставили свой асинхронный метод возвращать Task ??? Ну, это все еще не совсем верно. Теперь вы возвращаете задачу, которая будет находиться в неисправном состоянии из-за исключения, однако, поскольку вы никогда не ожидаете его, исключение никогда не «разворачивается» и фактически выбрасывается, поэтому тестирование успешно продолжается.

Что вам нужно сделать, это сделать тестовую асинхронность и вернуть задачу, а метод, который вы тестируете, сделать асинхронную задачу недействительной, и дождаться этого метода в своем тесте.

Вот так

[TestMethod]
public async Task Send_FailsOnWrongHostName()
{
    var name = "FailWithHostname";
    var msg = new Message(MyStates.Register, "UnitTest", "Test");

    try
    {
        var client = new PipeClient();
        await client.Send("lol", name, msg);
    }
    catch (Exception e)
    {
        Assert.IsTrue(e is ArgumentException);
    }
}

public class PipeClient : IPipeClient
{
    public async Task Send(string host, string pipeName, Message msg)
    {
        if (string.IsNullOrEmpty(msg.PreparedMessage))
            throw new ArgumentException("MESSAGE_NOT_FOUND");

        if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(pipeName))
            throw new ArgumentNullException();

        if (!host.TryParseHost()) 
            throw new ArgumentException("INVALID_HOST_NAME");

        using (var pipeClient = new NamedPipeClientStream(host, pipeName, PipeDirection.Out))
        {
            pipeClient.Connect(200);

            using (var writer = new StreamWriter(pipeClient))
            {
                await Task.Run(() => writer.WriteLine(msg.PreparedMessage));
                writer.Flush();
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...