Модульное тестирование, было ли обнаружено исключение - PullRequest
3 голосов
/ 02 апреля 2012

У меня есть метод, который нужно попробовать / поймать. Это потому, что метод вызывается из Task. Если выдается исключение, поток завершается. Я мог бы использовать Task.ContinueWith для обработки ошибок, а затем запустить новую задачу, если произошла ошибка, но попытка / уловка сработает.

Как бы то ни было, я знаю, что мне нужно добавить try / catch, но как мне проверить, что исключение поймано?

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

Ответы [ 4 ]

3 голосов
/ 03 апреля 2012

Если вы занимаетесь TDD, вы должны делать небольшие шаги и сосредоточиться на том, что должны делать ваши классы. Вот пример. Вы хотите распечатать некоторые отчеты. Во-первых (я полагаю, вы выходите за пределы) вы создаете класс Report, который должен печатать себя через Printer (это только для примера). Итак, вы пишете тест:

[Test]
public void ShouldPrintItself()
{
   Mock<IPrinter> printer = new Mock<IPrinter>();            
   Report report = new Report(printer.Object);
   report.Text = "foo";

   report.Print();
   printer.Verify(p => p.Print("foo"));
}

И вы пишете некоторую реализацию для report.Print метода. Также вы разрабатываете интерфейс IPrinter сейчас. Затем вы понимаете, что принтер иногда может показывать исключения (например, из бумаги). Это ваш случай, кстати. Таким образом, вы переименовываете report.Print метод во что-то вроде TryPrint, меняете первый тест и создаете новый:

[Test]
public void ShouldPrint()
{
    Mock<IPrinter> printer = new Mock<IPrinter>();            
    Report report = new Report(printer.Object);
    report.Text = "foo";

    Assert.True(report.TryPrint());
    printer.Verify(p => p.Print("foo"));
}

[Test]
public void ShouldNotPrint()
{
    Mock<IPrinter> printer = new Mock<IPrinter>();
    printer.Setup(p => p.Print(It.IsAny<string>())).Throws<Exception>();
    Report report = new Report(printer.Object);
    report.Text = "foo";

    Assert.False(report.TryPrint());
}

И вы возвращаетесь к TryPrint методу. Теперь вы добавляете блок try catch вокруг вызова к принтеру и проходите тесты (то же самое, что вы должны делать в приложении):

public bool TryPrint()
{
    try
    {
        _printer.Print(_text);
        return true;
    }
    catch (Exception ex)
    {
        // of course, log exception
        return false;
    }           
}

Когда вы закончите здесь, вы можете перейти к Printer созданию. В вашем случае это будут тесты компонентов. Хорошие новости - у вас уже есть интерфейс IPrinter. Итак, вы пишете тесты и проверяете, что в некоторых случаях будут выдаваться исключения:

[Test]
public void ShouldThrowExceptionWhenNoPaperLeft()
{
    Printer printer = new Printer();
    printer.PagesCount = 0;

    Exception ex = Assert.Throws<Exception>(() => printer.Print("foo"));
    Assert.That(ex.Message, Is.EqualTo("Out of paper"));
}

И, конечно, вы пишете свою компонентную реализацию, чтобы пройти этот тест. После этого ваш класс с блоком try catch работает как положено, а ваш компонент работает как положено, вызывая исключения, когда это необходимо.

1 голос
/ 02 апреля 2012

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

1 голос
/ 02 апреля 2012

То, что вы добавляете try / catch, означает, что у вас есть желаемое поведение, когда тестируемый класс вызывает другой, который выдает исключение. Try / catch - это «как», протестируйте поведение.

Итак, используя насмешку, выведите исключение при вызове «другой» службы и проверьте, что ваш класс делает то, что вам нужно. Сначала напишите тест, это заставит вас задуматься о том, почему вы хотите сделать попытку / поймать.

0 голосов
/ 02 апреля 2012

Это то, с чем я столкнулся, но было бы интересно узнать мнение людей:

[Test]
public void DoSomething_NullParameterEntered_ShouldCatchException()
{
    var component = new Whatever();

    try
    {
        component.DoSomething(null);  //If a try/catch block exists it will not fall into the below catch
    }
    catch
    {
        Assert.Fail();
    }
}
...