Open Mariachi1231 opened 3 years ago
This sounds reasonable. We already have a similar option with EnableBaseClassTestMethodsFromOtherAssemblies.
We are running into this problem as well, hopefully it can be fixed soon
Plus. The same for me.
It's a bit more complex for AssemblyInitialize
/AssemblyCleanup
because we cannot guarantee the location of these methods so we would need to iterate through all types and methods of other assemblies to find them which would highly increase discovery time. Also, you can then start to have base that also inherits from a base from another assembly, meaning we would also need to explore this assembly (etc etc).
Given current implementation, I am not in favour of implementing this feature.
I will keep the ticket open to collect feedback.
What if you had to specify the class at an assembly level to ensure that the discovery process can stay fast? I could really use this feature ^_^
Something like:
[assembly: AssemblyTestClass(typeof(TestBase))]
I love @ChristopherHaws's proposal!
We are currently defining the shared class with AssemblyInitialize/Cleanup
attributes in VS Shared Project.
What if you had to specify the class at an assembly level to ensure that the discovery process can stay fast? I could really use this feature ^_^
Something like:
[assembly: AssemblyTestClass(typeof(TestBase))]
That's definitely a possibility.
In the meantime, you could "easily" create a method in your project marked with assembly initialize attribute that would simply call the assembly initialize from the other assembly you reference. This is obviously only to provide a temporary workaround for you.
your project marked with assembly initialize attribute that would simply call the assembly initialize from the other assembly you reference. This is obviously only to provide a temporary workaround for you.
This is what we are doing currently :)
@Evangelink I think we could use a Roslyn source generator combined with a ModuleInitializer to support this seamlessly and without performance penalty?
A new API is added:
public static class AssemblyFixturesHelper
{
public void RegisterAssemblyInitialize(Action<TestContext> assemblyInitializeAction);
public void RegisterAssemblyCleanup(Action assemblyCleanupAction);
}
A source generator will look for [AssemblyInitialize]
and [AssemblyCleanup]
and generates the "registration" code in a ModuleInitializer.
For example, if you have in a library code like:
public class MyClass
{
[AssemblyInitialize]
public static void AssemblyIntialize(TestContext testContext)
{
}
[AssemblyCleanup]
public static void AssemblyCleanup()
{
}
}
The generated code will be something like:
namespace AssemblyName;
internal static class AssemblyFixtureModuleInitializer
{
[global::System.Runtime.CompilerServices.ModuleInitializerAttribute]
internal static void Initialize()
{
AssemblyFixturesHelper.RegisterAssemblyInitialize(MyClass.AssemblyInitialize);
AssemblyFixturesHelper.RegisterAssemblyCleanup(MyClass.AssemblyCleanup);
}
}
Good suggestion @Youssef1313. I have the idea to allow registration of lambdas/methods in addition to the reflection based discovery and that would fit nicely with it being called by the source gen. This way we avoid ModuleInit that would most likely not work with VSTest.
Description
Hi guys, I have been facing the behaviour of
AssemblyInitialize/AssemblyCleanup
logic where they are not executed if you have a TestClass, which is a child of some base class defined in another assembly. From some point of view, this seems partially reasonable. I slightly went through your code and found, that scanning of test classes is based onAssemblyEnumerator
and deciding whether a test assembly has someAssemblyInitialize
or not is based on that fact. And for sure, in case of another assembly, it decides that, well, the assembly has no appropriate signatures since test classes are defined within such assembly have no direct implementation ofAssemblyInitialize/AssemblyCleanup
and ignore the fact that such method can be defined in a base class of test classes.From another point of view, this seems slightly bad, since I am almost sure that most developers/teams/companies have their own infrastructure for tests where they are storing some useful cross-cutting logic, and since such infrastructure is generic, they, for sure, implement the logic for
AssemblyInitialize
and other lifecycle-based methods. And, for sure, a good idea for such guys is to dedicate their test infrastructure in a separate assembly, in order to reuse such logic across different projects/test-assemblies. But because of the limitations that I described above, unfortunately, it is not possible to do (without dirty workarounds).Steps to reproduce
[TestClass] public class UnitTest1 : TestBase { [TestMethod] public void TestMethod1() { result?.AppendLine(nameof(TestMethod1)); } }
AssemblyIntialize Test AssemblyCleanup