Как протестировать аспекты PostSharp? - PullRequest
13 голосов
/ 16 марта 2012

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

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

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

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

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

А потом, если так,

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

Ответы [ 2 ]

10 голосов
/ 16 марта 2012

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

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

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

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

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

В этой заметке вы также должны использовать проверку времени компиляции, которая также может предотвратить неправильное использование атрибутов. Иногда необходимо протестировать определенные условия, которые вы не можете описать с помощью синтаксиса Attribute, затем вступает в силу проверка времени компиляции. Это было для меня большим преимуществом и значительно сократило количество сеансов отладки в отношении аспектов 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 не является частью трассировки, оно больше связано с аспектом. Поскольку вы хотите иметь возможность проверить это, вам нужно как-то отделить его.
1 голос
/ 26 апреля 2013

Вопрос теперь рассматривается в справочной документации PostSharp:

http://doc.postsharp.net/postsharp-3.0/Content.aspx/PostSharp-3.0.chm/html/2ad6cf92-08eb-4537-a434-d88a3e493721.htm

...