Лучший способ протестировать исключения с Утверждает, чтобы гарантировать, что они будут брошены

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

 number_years = params[:end_year].to_i - params[:start_year].to_i + 1
 @sale_averages = Sale.joins(:shops, :items)
                      .select('items.name, AVG(sale.price) as price')
                      .where("EXTRACT(year from season_year) BETWEEN #{params[:start_year]} AND #{params[:end_year]}")
                      .where('shops.name': params[:select_shop])
                      .group('items.name')
                      .having("(COUNT(DISTINCT(EXTRACT(year from season_year))) = #{number_years})")

Я также использовал BETWEEN вместо < и >. Я думаю, что вы хотите сгруппировать по названию товара, а не по магазину (как это было в исходном запросе).

87
задан Hannoun Yassir 19 September 2014 в 13:03
поделиться

5 ответов

У меня есть пара различных шаблонов, которые я использую. Я использую атрибут ExpectedException большую часть времени, когда ожидается исключение. Этого достаточно для большинства случаев, однако в некоторых случаях этого недостаточно. Исключение не может быть перехвачено - так как оно генерируется методом, который вызывается отражением - или, возможно, я просто хочу проверить, выполняются ли другие условия, скажем, откат транзакции или какое-то значение все еще установлено. В этих случаях я обертываю его в блок try / catch , который ожидает точное исключение, выполняет Assert.Fail , если код выполняется успешно, а также перехватывает общие исключения, чтобы убедиться, что другой исключение не выдается.

Первый случай:

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MethodTest()
{
     var obj = new ClassRequiringNonNullParameter( null );
}

Второй случай:

[TestMethod]
public void MethodTest()
{
    try
    {
        var obj = new ClassRequiringNonNullParameter( null );
        Assert.Fail("An exception should have been thrown");
    }
    catch (ArgumentNullException ae)
    {
        Assert.AreEqual( "Parameter cannot be null or empty.", ae.Message );
    }
    catch (Exception e)
    {
        Assert.Fail(
             string.Format( "Unexpected exception of type {0} caught: {1}",
                            e.GetType(), e.Message )
        );
    }
}
129
ответ дан Jim Aho 24 November 2019 в 07:43
поделиться

Я новичок здесь, и у меня нет репутации комментировать или понижать голос, но я хотел указать на недостаток в примере в ответ Энди Уайта :

try
{
    SomethingThatCausesAnException();
    Assert.Fail("Should have exceptioned above!");
}
catch (Exception ex)
{
    // whatever logging code
}

Во всех известных мне модульных средах тестирования Assert.Fail работает путем генерирования исключения, поэтому общий перехват фактически маскирует провал теста. Если SomethingThatCausesAnException () не выбрасывает, Assert.Fail будет, но это никогда не будет всплывать для тестового бегуна, чтобы указать на сбой.

Если вам нужно поймать ожидаемый исключение (т. е. для утверждения определенных деталей, таких как сообщение / свойства исключения), важно отлавливать определенный ожидаемый тип, а не базовый класс Exception. Это позволило бы утверждать.

17
ответ дан Community 24 November 2019 в 07:43
поделиться

В качестве альтернативы использованию атрибута ExpectedException я иногда определяю два полезных метода для своих тестовых классов :

AssertThrowsException () принимает делегата и утверждает, что выдает ожидаемое исключение с ожидаемым сообщением.

AssertDoesNotThrowException () принимает тот же делегат и утверждает, что не выдает исключение.

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

Используя их, мой код модульного теста может выглядеть следующим образом:

ExceptionThrower callStartOp = delegate(){ testObj.StartOperation(); };

// Check exception is thrown correctly...
AssertThrowsException(callStartOp, typeof(InvalidOperationException), "StartOperation() called when not ready.");

testObj.Ready = true;

// Check exception is now not thrown...
AssertDoesNotThrowException(callStartOp);

Хорошо и аккуратно, да?

Мои методы AssertThrowsException () и AssertDoesNotThrowException () определены в Общий базовый класс выглядит следующим образом:

protected delegate void ExceptionThrower();

/// <summary>
/// Asserts that calling a method results in an exception of the stated type with the stated message.
/// </summary>
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param>
/// <param name="expectedExceptionType">The expected type of the exception, e.g. typeof(FormatException).</param>
/// <param name="expectedExceptionMessage">The expected exception message (or fragment of the whole message)</param>
protected void AssertThrowsException(ExceptionThrower exceptionThrowingFunc, Type expectedExceptionType, string expectedExceptionMessage)
{
    try
    {
        exceptionThrowingFunc();
        Assert.Fail("Call did not raise any exception, but one was expected.");
    }
    catch (NUnit.Framework.AssertionException)
    {
        // Ignore and rethrow NUnit exception
        throw;
    }
    catch (Exception ex)
    {
        Assert.IsInstanceOfType(expectedExceptionType, ex, "Exception raised was not the expected type.");
        Assert.IsTrue(ex.Message.Contains(expectedExceptionMessage), "Exception raised did not contain expected message. Expected=\"" + expectedExceptionMessage + "\", got \"" + ex.Message + "\"");
    }
}

/// <summary>
/// Asserts that calling a method does not throw an exception.
/// </summary>
/// <remarks>
/// This is typically only used in conjunction with <see cref="AssertThrowsException"/>. (e.g. once you have tested that an ExceptionThrower
/// method throws an exception then your test may fix the cause of the exception and then call this to make sure it is now fixed).
/// </remarks>
/// <param name="exceptionThrowingFunc">Delegate that calls the method to be tested.</param>
protected void AssertDoesNotThrowException(ExceptionThrower exceptionThrowingFunc)
{
    try
    {
        exceptionThrowingFunc();
    }
    catch (NUnit.Framework.AssertionException)
    {
        // Ignore and rethrow any NUnit exception
        throw;
    }
    catch (Exception ex)
    {
        Assert.Fail("Call raised an unexpected exception: " + ex.Message);
    }
}
9
ответ дан GrahamS 24 November 2019 в 07:43
поделиться

Пометьте тест с помощью ExpectedExceptionAttribute (это термин в NUnit или MSTest; пользователям других платформ модульного тестирования может потребоваться перевести).

4
ответ дан itowlson 24 November 2019 в 07:43
поделиться

В большинстве каркасов модульного тестирования .net вы можете поместить атрибут [ExpectedException] в метод теста. Однако это не может сказать вам, что исключение произошло в тот момент, когда вы ожидали этого. Вот где xunit.net может помочь.

С xunit у вас есть Assert.Throws, так что вы можете делать такие вещи:

    [Fact]
    public void CantDecrementBasketLineQuantityBelowZero()
    {
        var o = new Basket();
        var p = new Product {Id = 1, NetPrice = 23.45m};
        o.AddProduct(p, 1);
        Assert.Throws<BusinessException>(() => o.SetProductQuantity(p, -3));
    }

[Факт] является эквивалентом [TestMethod] блока Xunit

3
ответ дан Steve Willcock 24 November 2019 в 07:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: