I’m trying to create a custom attribute that will work in a sort-of AOP way (I don’t have access to postsharp, unfortunately and I’m not very familiar with Unity). It has AttributeUsage.Method and in its constructor it configures some parts of the test environment (pulls some info out of app.config and calls some exes that config the environment).
It works, except that right now, when I build the solution, the attribute is executed – which is undesireable.
Is there a way to create a custom attribute that isn’t executed at compile time?
edit> I guess an example usage might help:
public void Scenario1Tests
{
[Test]
[Environment(Environments.A)]
public void Scenario1TestA()
{
Assert.Something();
}
[Test]
[Environment(Environments.Any)]
public void Scenario1TestB()
{
Assert.SomethingElse();
}
}
// Most tests will be written environment independent, some must not
public enum Environments
{
A,
B,
Any
};
[AtrributeUsage(AttributeTargets.Method)]
public void Environment : Attribute
{
public Environment(Environments env)
{
// lots of test can have this attribute, requirement is
// that it is only configured once as it is a lengthy configuration
if (this.EnvironmentIsAlreadyConfigured())
return;
this.GetSettingsFromAppConfig();
Process.Start(/* ... */); // can take 20 mins+
}
public Environment()
: this(Environments.Any)
{
}
}
The usual method is to use the attribute strictly as a marker. You configure it in the constructor, but take no actions. Then, at runtime, you inspect the methods via reflection, extract the configuration information from the attribute, and take the appropriate actions based on that information.
For example, if you wanted an attribute that checked parameters for null prior to executing the method, you could create it like so:
Then, mark your method as such:
Then, in your code, get the
Foomethod via reflection, and check it for the attribute:Update: Since you need this in a scenario where MSTest is running the method, you should take a look at this article, which discusses how to hook into the testing process. Basically, you need to extended from
ContextBoundObject, and intercept the method calls to perform the attribute processing you want.Update 2: Given what the attribute does, I would probably just make the environment setup a method, and call it from the beginning of the appropriate tests. I don’t think you gain all that much by having an attribute. Alternatively, you could divide your fixtures by environment, and have the environment setup/teardown performed in the fixture setup/teardown. Either way is probably a lot easier than trying to make AOP work here, especially given the “do it once” nature of the attribute.