Testing Fabrics

Short of actually creating a project that covers all of the bases that one would want to cover is there a way to test fabrics present in Metalama that I have somehow missed?
10 Replies
Petr Onderka
Petr Onderka13mo ago
You should be able to use the regular Metalama.Testing.AspectTesting approach to test fabrics too. Each test file is effectively treated as a separate project.
addabis
addabis13mo ago
If you'd like to test that the fabric correctly works across projects, you can use the <Test>.Dependency.cs which causes the test runner to create two projects - the first project that includes <Test>.cs and references the second project which contains <Test>.Dependency.cs.
domsinclair
domsinclair13mo ago
Indeed that does seem to work, thanks. @addabis I have a whole set of fabric extensions that I'd like to test, so it may well be that your suggestion would make eminent sense in this case. Is there an example of that anywhere in the documentation?
addabis
addabis13mo ago
I don't think it's used in public repos at the moment. I'm mentioning that since it's rather a small note in https://doc.metalama.net/conceptual/aspects/testing/aspect-testing under "Creating a dependent project". We use that quite extensively though.
domsinclair
domsinclair13mo ago
Your right about it being a small note, however let's see if I can make sense of it. This was the first test that I created;
c#
using Metalama.Framework.Aspects;
using Metalama.Framework.Code;
using Metalama.Framework.Fabrics;

namespace VtlSoftware.Logging.Tests
{
internal class LogAllPublicMethodsTest1
{
#region Private Methods
private void DoSomethingElse()
{
}

#endregion

#region Public Methods
public int Add(int a, int b) { return a + b; }
public void DoSomething()
{
}

#endregion
}

internal class Fabric : ProjectFabric
{
#region Public Methods
public override void AmendProject(IProjectAmender amender) { amender.LogAllPublicMethods(); }

#endregion
}

[CompileTime]
public static class FabricExtensions
{
#region Public Methods

public static void LogAllPublicMethods(this IProjectAmender amender)
{
amender.Outbound
.SelectMany(compilation => compilation.AllTypes)
.Where(
type => type.Accessibility is Accessibility.Public or Accessibility.Internal &&
!type.IsStatic ||
type.Attributes.OfAttributeType(typeof(NoLogAttribute)).Any())
.SelectMany(type => type.Methods)
.Where(method => method.Accessibility is Accessibility.Public && method.Name != "ToString")
.AddAspectIfEligible<LogMethodAttribute>();
}

#endregion
}
}
c#
using Metalama.Framework.Aspects;
using Metalama.Framework.Code;
using Metalama.Framework.Fabrics;

namespace VtlSoftware.Logging.Tests
{
internal class LogAllPublicMethodsTest1
{
#region Private Methods
private void DoSomethingElse()
{
}

#endregion

#region Public Methods
public int Add(int a, int b) { return a + b; }
public void DoSomething()
{
}

#endregion
}

internal class Fabric : ProjectFabric
{
#region Public Methods
public override void AmendProject(IProjectAmender amender) { amender.LogAllPublicMethods(); }

#endregion
}

[CompileTime]
public static class FabricExtensions
{
#region Public Methods

public static void LogAllPublicMethods(this IProjectAmender amender)
{
amender.Outbound
.SelectMany(compilation => compilation.AllTypes)
.Where(
type => type.Accessibility is Accessibility.Public or Accessibility.Internal &&
!type.IsStatic ||
type.Attributes.OfAttributeType(typeof(NoLogAttribute)).Any())
.SelectMany(type => type.Methods)
.Where(method => method.Accessibility is Accessibility.Public && method.Name != "ToString")
.AddAspectIfEligible<LogMethodAttribute>();
}

#endregion
}
}
I currently have seven fabric extensions that I'd like to test, and to do that properly I'd need to have a variety of different class signatures and method signatures for them to run over.
I now know that I can create separate tests for each scenario, I'm wondering if your suggestion would allow them all to be tested at once in some way.
addabis
addabis13mo ago
My suggestion was intended only for the cross assembly scenario, i.e. when it is relevant that your fabric is being inherited in another project than the one in which it was applied. If you need to share code between test cases, you might want to have a look at the "Include other files" section. But the target code (the transformed code you are testing aspects on) always needs to be a part of the test file and cannot be shared between tests.
Gael Fraiteur
Gael Fraiteur13mo ago
GitHub
Metalama.Extensions/src/Metalama.Extensions.Architecture at master ...
Open-source extensions to Metalama.Framework. Contribute to postsharp/Metalama.Extensions development by creating an account on GitHub.
Gael Fraiteur
Gael Fraiteur13mo ago
GitHub
Metalama.Extensions/src/tests/Metalama.Extensions.Architecture.Aspe...
Open-source extensions to Metalama.Framework. Contribute to postsharp/Metalama.Extensions development by creating an account on GitHub.
Gael Fraiteur
Gael Fraiteur12mo ago
@domsinclair Can we close this conversation?
domsinclair
domsinclair12mo ago
Yes, certainly.
Want results from more Discord servers?
Add your server
More Posts
Eligibility MustNotHaveAspectOfTypeI want to have intellisense show a red squiggle under and attribute if it is added to a method that Test should surely either both pass or both failWithin the following repository (https://github.com/domsinclair/VtlSoftware.LoggingAspects) there arTesting IssueI've followed the basic instructions in the Documentation for testing Aspects (https://doc.metalama.Has anyone tried the Ctrl + . refactor menu recently?According to the documentation Invoking Ctrl + . to pull up the refactor menu should (if they are avIs it possible to mix aspects that call different parts of a class (ie Methods and Properties)?Pretty much as per the subject line. Consider the following scenario where one has aspects to log mIs this section of the documentation wrong?I'm looking at the following topic (https://doc.metalama.net/conceptual/using/fabrics/adding-aspectsWhy is it indicating I have compile-time code despite not?See the screenshot - Is there some way to decorate this to make clear that nothing in the class contHow do I invoke (and cast) an introduced generically typed field?Bear with me - there's a lot going on here. Also Discord is funky about styling my code, so I'm handIntegration with VS to display introduced elements in partial classesI can use compile-time generated elements from my run-time code by marking a class as partial, but IInterpolatedStringHandlerI'm experimenting with the InterpolatedStringHandler. The idea, in simple terms is to do away with