Подтвердить что ты не робот

Как unit test аспекты PostSharp?

После запроса question о внедрении аспекта с PostSharp мне пришло в голову, что мне, возможно, придется обновить код этого аспекта в будущем, и что я не хотел рисковать сломать все после этого.

Итак, я начал думать об модульном тестировании.

Мой первый вопрос:

Уместно ли думать о модульном тестировании аспект?

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

И тогда, если да,

Как реализовать модульное тестирование для аспектов PostSharp?

4b9b3361

Ответ 1

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

Однако вам нужно разделить это на две части:

  • Тестирование фактической функциональности аспекта
  • Проверка работоспособности контекстного извлечения, которая используется для фактического выполнения функциональных возможностей.

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

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

В этой заметке вы также должны использовать проверку времени компиляции, что также может помешать вам использовать атрибуты неправильным образом. Иногда необходимо проверить определенные условия, которые невозможно описать с помощью синтаксиса атрибута, а затем выполнить проверку времени компиляции. Это было большим преимуществом для меня и значительно сократило количество отладочных сессий в отношении аспектов PostSharp, см.:
http://www.sharpcrafters.com/postsharp/robustness

Вот какой-то очень простой пример кода, ничего не DI, просто чтобы проиллюстрировать, как разделить вещи:

public sealed class TraceAttribute : OnMethodBoundaryAspect
{
    private readonly string category;
    private TraceArgumentService argumentService;
    private TraceService traceService;

    public string Category { get { return category; } }

    public TraceAttribute(string category)
    {
        this.category = category;
    }

    public override void RuntimeInitialize(System.Reflection.MethodBase method)
    {
        base.RuntimeInitialize(method);
        this.argumentService = new TraceArgumentService();
        this.traceService = new TraceService();
    }


    public override void OnEntry(MethodExecutionArgs args)
    {                
        traceService.Write(
            argumentService.GetDeclaringTypeName(args),
            argumentService.GetMethodName(args),
            category);

    }
}

public class TraceArgumentService
{
    public string GetDeclaringTypeName(MethodExecutionArgs args)
    {
        return args.Method.DeclaringType.Name;
    }

    public string GetMethodName(MethodExecutionArgs args)
    {
        return args.Method.Name;
    }
}

public class TraceService
{
    public void Write(string declaringTypeName, string methodName, string category)
    {
        Trace.WriteLine(string.Format("Entering {0}.{1}.",
            declaringTypeName, methodName), category);
    }
}

Вы можете спросить, почему TraceService и отдельный TraceArgumentService:

  • Логика трассировки должна быть независимой от PostSharp, поэтому она не должна знать о MethodExecutionArgs.
  • Извлечение аргументов из MethodExecutionArgs не является частью трассировки, оно больше связано с аспектом. Поскольку вы хотите проверить его, вам нужно как-то отделить его.