Как в UnitTest протестировать такой атрибут?
От: Cynic Россия  
Дата: 17.04.11 16:03
Оценка:
Иногда нужно было мне узнать, что тест выкинул исключение определённого типа с определёнными параметрами или сообщением. Воспользовавшись подсказкой ksg71
Автор: ksg71
Дата: 15.04.11
, написал такой атрибут:
        public class ExpectedExceptionAndMessageAttribute : ExpectedExceptionBaseAttribute
        {
            private readonly Type expectedType;
            private readonly string expectedMessage;

            public ExpectedExceptionAndMessageAttribute(Type expectedExceptionType, string expectedExceptionMessage)
            {
                if (Equals(expectedExceptionType, null))
                    throw new ArgumentNullException("expectedExceptionType");

                if (Equals(expectedExceptionMessage, null))
                    throw new ArgumentNullException("expectedExceptionMessage");

                expectedType = expectedExceptionType;
                expectedMessage = expectedExceptionMessage;
            }

            protected override void Verify(Exception actualException)
            {
                Microsoft.VisualStudio.TestTools.UnitTesting.
                    Assert.AreNotEqual(actualException, null);
                Microsoft.VisualStudio.TestTools.UnitTesting.
                    Assert.AreEqual(expectedType, actualException.GetType());
                Microsoft.VisualStudio.TestTools.UnitTesting.
                    Assert.AreEqual(expectedMessage, actualException.Message);
            }
        }

Далее встал вопрос как его протестировать. В случае когда ожидаемое исключение и сообщения совпадают с реальными всё просто, тест проходит успешно.
        [TestMethod]
        [ExpectedExceptionAndMessage(typeof(DivideByZeroException), "Attempted to divide by zero.")]
        public void ExpectedExceptionAndMessageAllExcpectedTest()
        {
            throw new DivideByZeroException();
        }

Следующей задачей было проверить, что будет если, например, ожидаемое исключение не совпадёт с реальным. Сделал, так:
        [TestMethod]
        [ExpectedExceptionAndMessage(typeof(ArgumentException), "Value does not fall within the expected range.")]
        public void ExpectedExceptionAndMessageMessageIsExcpectedTest()
        {
            throw new DivideByZeroException();
        }

Проблема в том, что исключение генерируется самим атрибутом, который в тестовый метод не входит, поэтому такой тест будет провален. Можно конечно создать экземпляр класса, а потом используя отражение вызвать метод Verify с нужными параметрами. Но я решил для начала поинтересоваться, есть ли ещё способы как-то его протестировать Например, можно ли указать студии, что провал теста означает его удачное прохождение Ну и код поругайте на всякий случай
:)
Re: Как в UnitTest протестировать такой атрибут?
От: ksg71 Германия  
Дата: 18.04.11 06:58
Оценка:
Здравствуйте, Cynic, Вы писали:

а чем стандартный ExpectedExceptionAttribute не подходит?
ну если этот нужно протестировать, то как и любой другой тип, пишете тесты конструктора и метода Verify,
до него лучше добраться отнаследовавшись (сделав некий TestableExpectedExceptionAndMessageAttribute)
рефлекшн не удобно, ислючения будут завернутыми в TargetInvocationException
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[2]: Как в UnitTest протестировать такой атрибут?
От: Cynic Россия  
Дата: 18.04.11 12:08
Оценка:
Здравствуйте, ksg71, Вы писали:

K>Здравствуйте, Cynic, Вы писали:


K>а чем стандартный ExpectedExceptionAttribute не подходит?

K>ну если этот нужно протестировать, то как и любой другой тип, пишете тесты конструктора и метода Verify,
K>до него лучше добраться отнаследовавшись (сделав некий TestableExpectedExceptionAndMessageAttribute)
K>рефлекшн не удобно, ислючения будут завернутыми в TargetInvocationException

Зато с рефлекшеном весь тест в 10-ть строк умещается. А TargetInvocationException можно и развернуть, добравшись до InnerException
Я просто думал, что можно ещё как-то это исполнить. Про наследование, что-то не подумал
:)
Re: Как в UnitTest протестировать такой атрибут?
От: alex4Zero Россия  
Дата: 19.04.11 06:53
Оценка:
если цель — протестировать тип исключения и сообщение, можно поступить так:


public static class Expect {
    public void ApplicationException(Action action, string expectedMessage) {
        try {
             action();
             Assert.Fail("Application Exception is expected")
        }
        catch (ApplicationException e) {
             Assert.AreEqual(expectedMessage, e.Message);
        }
    }
}


ну или более обобщенно так —

public void ExceptionOf<T>(Action action, string expectedMessage) where T: Exception {
        try {
             action();
             Assert.Fail("Application Exception is expected")
        }
        catch (T e) {
             Assert.AreEqual(expectedMessage, e.Message);
        }
    }
Re[2]: Как в UnitTest протестировать такой атрибут?
От: Cynic Россия  
Дата: 19.04.11 08:07
Оценка:
Здравствуйте, alex4Zero, Вы писали:

Z>если цель — протестировать тип исключения и сообщение, можно поступить так:

Согласен. Только лучше тогда уж так:

public void ExceptionOf<T>(Action action, string expectedMessage) where T: Exception 
{
    try 
    {
         action();
    }
    catch (T e)
    {
         Assert.AreEqual(typeof(T), e.GetType());
         Assert.AreEqual(expectedMessage, e.Message);
    }
}
:)
Re[3]: Как в UnitTest протестировать такой атрибут?
От: alex4Zero Россия  
Дата: 19.04.11 08:11
Оценка:
Здравствуйте, Cynic, Вы писали:

C>Здравствуйте, alex4Zero, Вы писали:


Z>>если цель — протестировать тип исключения и сообщение, можно поступить так:

C>Согласен. Только лучше тогда уж так:

C>
C>public void ExceptionOf<T>(Action action, string expectedMessage) where T: Exception 
C>{
C>    try 
C>    {
C>         action();
C>    }
C>    catch (T e)
C>    {
C>         Assert.AreEqual(typeof(T), e.GetType());
C>         Assert.AreEqual(expectedMessage, e.Message);
C>    }
C>}
C>



Assert.AreEqual(typeof(T), e.GetType()); — бессмысленно. Этим вы тестируете то, что catch в .NET работает правильно.
Обязательно добавьте Assert.Fail после вызова action(); иначе, если исключения не случится — тест будет зеленым, что не верно
Re[4]: Как в UnitTest протестировать такой атрибут?
От: Cynic Россия  
Дата: 19.04.11 08:14
Оценка:
Здравствуйте, alex4Zero, Вы писали:

Z>Assert.AreEqual(typeof(T), e.GetType()); — бессмысленно. Этим вы тестируете то, что catch в .NET работает правильно.

Z>Обязательно добавьте Assert.Fail после вызова action(); иначе, если исключения не случится — тест будет зеленым, что не верно

Сорри. Имелось ввиду:

public void ExceptionOf<T>(Action action, string expectedMessage) where T: Exception 
{
    try 
    {
         action();
    }
    catch (Exception e)
    {
         Assert.AreEqual(typeof(T), e.GetType());
         Assert.AreEqual(expectedMessage, e.Message);
    }
}
:)
Re[4]: Как в UnitTest протестировать такой атрибут?
От: alex4Zero Россия  
Дата: 19.04.11 08:17
Оценка:
Z>Assert.AreEqual(typeof(T), e.GetType()); — бессмысленно. Этим вы тестируете то, что catch в .NET работает правильно.
Z>Обязательно добавьте Assert.Fail после вызова action(); иначе, если исключения не случится — тест будет зеленым, что не верно

Assert.AreEqual(typeof(T), e.GetType()) — хотя да, это можно оставить на случай, если вы перехватываете базовый тип исключения
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.