Затвердіть виняток за допомогою XUnit


111

Я новачок у XUnit та Moq. У мене є метод, який приймає рядок як аргумент. Як обробити виняток за допомогою XUnit.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException() {
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    var result = profiles.GetSettingsForUserID("");
    //assert
    //The below statement is not working as expected.
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

Метод, що перевіряється

public IEnumerable<Setting> GetSettingsForUserID(string userid)
{            
    if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
    var s = profiles.Where(e => e.UserID == userid).SelectMany(e => e.Settings);
    return s;
}

1
Що ви маєте на увазі під "не працює так, як очікувалося"? (Крім того, будь ласка, форматуйте свій код більш читальним. Використовуйте попередній перегляд та публікуйте повідомлення, коли буде виглядати, як ви хотіли б виглядати, якби читали його.)
Джон Скіт

4
Підказка: ви телефонуєте, GetSettingsForUserID("")перш ніж почати телефонувати Assert.Throws. Assert.ThrowsВиклик не може допомогти. Я б запропонував бути менш жорстким щодо AAA ...
Джон Скіт

Відповіді:


183

Assert.Throws вираз буде ловити виключення і стверджувати тип. Однак ви викликаєте тестований метод поза висловленням ствердження і, таким чином, випадаєте з ладу тестового випадку.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    // act & assert
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

Якщо нахилятися від наступного AAA, ви можете дістати дію до власної змінної.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    Action act = () => profiles.GetSettingsForUserID("");
    //assert
    var exception = Assert.Throws<ArgumentException>(act);
    //The thrown exception can be used for even more detailed assertions.
    Assert.Equal("expected error message here", exception.Message);
}

Зверніть увагу, як виняток також може використовуватися для детальних тверджень про режим


5
Якщо використовують методи асинхронізації, Visual Studio видає попередження з вищевказаним синтаксисом. Він вважає за краще це:async Task act() => await service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);
Алек

5
Насправді для мене, що призвело до помилки, "не можна неявно перетворити Завдання у функцію <Завдання>", тоді як якщо я просто кажу, Task act() => service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);то це задоволено і працює добре.
Алек

як робота з асинхронізуванням / очікуванням впливає на це? коли я намагаюся зробити це за допомогою ThrowAsync в моєму тесті, він ніколи не доходить до лінії Assert.Equal, оскільки він успішно видає помилку і закриває тест. випробування води, щоб побачити, чи не повинно це бути новим питанням ...
nathanjw

@AlecDenholm Дякую! Це єдине, що працювало на мене. Я думаю, що деякі інші пропозиції насправді не працюють належним чином для асинхронних речей.
торгова марка

45

Якщо ви хочете бути жорсткими щодо AAA, тоді ви можете використовувати Record.Exception від xUnit для зйомки винятку на етапі акту.

Потім ви можете робити твердження на основі захопленого винятку на етапі звіту.

Приклад цього можна побачити в тестах xUnits .

[Fact]
public void Exception()
{
    Action testCode = () => { throw new InvalidOperationException(); };

    var ex = Record.Exception(testCode);

    Assert.NotNull(ex);
    Assert.IsType<InvalidOperationException>(ex);
}

Від вас залежить, який шлях ви хочете пройти, і обидва шляхи повністю підтримуються тим, що надає xUnit.


1
FWIW, Це рішення чудово, якщо вам потрібно, можливо, підтвердити повідомлення про виключення тощо. Я думаю, що саме тоді ви можете використовувати Record.Exception.
Джефф Лафай

@JeffLaFay Я ціную, що я трохи запізнююся на вечірку тут, чим це буде відрізнятися від використання var exception = Assert.Throws<InvalidOperationException>(testCode);та затвердження exception.Message? чи це просто інший аромат досягнення того ж самого?
ColinM

3

Ви можете розглянути щось подібне, якщо хочете дотримуватися AAA:

// Act 
Task act() => handler.Handle(request);

// Assert
await Assert.ThrowsAsync<MyExpectedException>(act);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.