Multiple CollectionDefinition per test class in XUnit - c#

We have many XUnit tests in our project that we use to test our API (each with many InlineData). The problem is that we can access a subset of the API via two other connection methods.
Today we use a CollectionDefinition to keep the connection to the main API (it is time consuming to create the connection) and we intend to have three separate CollectionDefinition, one for each connection path.
I imagine I will create a new attribute I can add to each test class to tell which connection methods it should use. And then it uses the CollectionDefinitions that are connected to the various connections.
I am considering using [assembly: Xunit.TestFramework ("name", "assembly")] and implementing my own XunitTestFramework. But I can not figure out how to achieve what I want. Do you have any suggestions on how I should proceed?

You can accomplish this as follows:
Make an abstract class that defines the methods common to all your API's, and derive specific classes from it which create the specific connection. Make a CollectionDefinition and a fixture for each type of connection:
using Xunit;
namespace SO71300821_multipleCollectionDefinition
{
public abstract class APIConnectionMethod
{
public bool isOK { get; } = true;
};
public class APIConnectionMethod0 : APIConnectionMethod
{
public APIConnectionMethod0()
{
// ... initialize API connection ...
}
}
[CollectionDefinition("Collection0")]
public class Collection0 : ICollectionFixture<APIConnectionMethod0>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
public class APIConnectionMethod1 : APIConnectionMethod
{
public APIConnectionMethod1()
{
// ... initialize API connection ...
}
}
[CollectionDefinition("Collection1")]
public class Collection1 : ICollectionFixture<APIConnectionMethod1>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
public class APIConnectionMethod2 : APIConnectionMethod
{
public APIConnectionMethod2()
{
// ... initialize API connection ...
}
}
[CollectionDefinition("Collection2")]
public class Collection2 : ICollectionFixture<APIConnectionMethod2>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
}
Make an abstract base test class that implements all the tests that need to work for each of the various API's:
using Xunit;
namespace SO71300821_multipleCollectionDefinition
{
public abstract class UnitTestBase
{
APIConnectionMethod connection;
public UnitTestBase(APIConnectionMethod connection_)
{
connection = connection_;
}
[Fact]
public void connectionIsOK()
{
Assert.NotNull(connection);
Assert.True(connection.isOK);
}
}
}
Derive a public class from the base test class for each type of connection:
using Xunit;
namespace SO71300821_multipleCollectionDefinition
{
[Collection("Collection0")]
public class UnitTestSpecific0 : UnitTestBase
{
public UnitTestSpecific0(APIConnectionMethod0 connection_) : base(connection_)
{
}
}
[Collection("Collection1")]
public class UnitTestSpecific1 : UnitTestBase
{
public UnitTestSpecific1(APIConnectionMethod1 connection_) : base(connection_)
{
}
}
[Collection("Collection2")]
public class UnitTestSpecific2 : UnitTestBase
{
public UnitTestSpecific2(APIConnectionMethod2 connection_) : base(connection_)
{
}
}
}
If there are tests that only work for certain specific types of connections, you can implement them in these classes.
The test discoverer will find the tests in UnitTestBase in each of the derived classes and run them in those classes, so you'll have a separate test in the Test Explorer for each of the derived classes.
The information from https://xunit.net/docs/shared-context helped me prepare this answer and some of the code is copied from there.

Related

How to get the name of the instance disposed by using reflection

I am building some integration tests for my database stored procedures.
I have setup an xUnit project and implemented Fixture pattern. To show you:
public class MyTableTest : IClassFixture<DatabaseFixture>
{
public MyTableTest()
{
//DO SOMETHING
}
[Fact]
public void Test()
{
//DO SOMETHING
}
}
And:
public class DatabaseFixture : IDisposable
{
public void Dispose()
{
// ... clean up test data from the database ...
}
}
This DatabaseFixture is something that will be shared among all of my test classes. Why? Because I want some common logic happening at the end of every test, such as cleanup.
Point is that I need to know which table to clean, which in my example would be MyTable. Such information I would retrieve by using reflection when the Dispose method will run against the instance of MyTableTest being disposed . How can I achieve this? Is it even possible (and correct) trying to achieve this? Thanks in advance.
You can have a TableName property in the DatabaseFixture class. Then receive an instance of the class in constructor of your test classes and set that TableName property. Later you can use it in dispose to do some cleanup.
public class MyTableTest : IClassFixture<DatabaseFixture>
{
DatabaseFixture databaseFixture;
public MyTableTest(DatabaseFixture databaseFixture)
{
this.databaseFixture = databaseFixture;
databaseFixture.TableName = "MyTable";
}
[Fact]
public void Test()
{
}
}
public class DatabaseFixture : IDisposable
{
//...
public string TableName { get; set; }
//...
public void Dispose()
{
// Cleanup based on TableName
}
}
To learn more about sharing context in xUnit, take a look at:
Shared Context between Tests
Comparing xUnit.net to other frameworks
You can use custom attributes to attach any arbitrary data to your derived Fixture class.
For example
you can create a TableNameAttribute like this:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TableNameAttribute : Attribute
{
public string Name { get; }
public TableNameAttribute(string name)
{
this.Name = name;
}
}
you can apply this attribute to your derived fixture class:
[TableName("MyTable")]
public class MyTableFixture : DatabaseFixture { }
you can use that fixture class inside your test
public class MyTableTest : IClassFixture<MyTableFixture>
{
[Fact]
public void Test()
{
//DO SOMETHING
}
}
Finally this is how you can retrieve the Name from the Dispose method:
public abstract class DatabaseFixture : IDisposable
{
...
public void Dispose()
{
var attribute = this.GetType().GetCustomAttribute(typeof(TableNameAttribute));
if (attribute is TableNameAttribute tableNameAttr)
Console.WriteLine(tableNameAttr.Name);
}
}
Is it even possible (and correct) trying to achieve this?
No. Reflection cannot tell type T in what context T is used; reflection only sees T's declaration.
More specific to your situation, reflection cannot tell type DatabaseFixture that it is being used as a type parameter of generic interface IClassFixture in the declaration of MyTableTest. In other words, for this set of declarations,
class A { }
class B <T> { }
class C : B<A> { }
A cannot reflectively determine that it is used in C's declaration, but C can know about its usage of A:
typeof(C)
.BaseType // B
.GetGenericArguments()[0] // A
How can I achieve this?
Depending on how you are using DatabaseFixture, you could get the calling test class using the StackTrace (if you are really bent on using reflection). Here is a simple example:
public class DisposableObject : System.IDisposable
{
public void Dispose()
{
var stack = new System.Diagnostics.StackTrace();
// This will log the name of the class that instantiated and disposed this.
System.Console.WriteLine(stack.GetFrame(1).GetMethod().DeclaringType.Name);
return;
}
}
If your DatabaseFixture is not called directly from your test class, you will either have to know the offset to pass to GetFrame(int), or you will need to search each frame until you find the first DeclaringType that matches your requirements (e.g., BaseType is IClassFixture with Generic Argument DatabaseFixture), something like this:
System.Type testClassType = new StackTrace()
.GetFrames()
.Where(f =>
{
System.Type baseType = f.GetMethod().DeclaringType.BaseType;
return typeof(IClassFixture<DatabaseFixture>).IsAssignableFrom(baseType);
})
.FirstOrDefault() // First matching result (assuming you found any)
?.GetMethod() // Get the reflected Method
.DeclaringType; // Get the type (e.g. class) that declares this method.
string tableName = testClassType.Name.Replace("Test", "");
Otherwise, you will need to set the table name manually, as suggested by Reza and Peter.

Workaround for Injecting a service into an abstract class to be available in subclasses - asp.net core

Update
Well, I wasn't sure what I was asking for so it got a bit of an XY-question/discussion.
Main problem now is that I have an abstract base class which can be seen as a service, and sub services that derives from it (properties / abstract methods).
I've tried workarounds with using Interface, but no luck. I do not need the IOtherService in my Controller, so I don't want to inject it there.
Startup:
services.AddTransient<IMyBaseService, MyBaseService>();
Base service:
public MyBaseService(IOtherService other)
{
OtherService = other;
}
public MyBaseService()
{
// this runs
}
Derived service
public class DerivedService : MyBaseService
{
public DerivedService(string x)
{
}
public DoStuff()
{
OtherService.RunSomething();
}
}
I just need IOtherService to be injected in my Base service so my child "services" can use it from an inherited property.
Or is this an example of property injection?
Base class:
public abstract class Vehicle : ICleanVehicle
{
private readonly ICleanVehicle _cleanVehicle;
public Vehicle(ICleanVehicle cleanVehicle)
{
if (cleanVehicle == null) throw new ArgumentNullException("cleanVehicle");
_cleanVehicle = cleanVehicle;
}
}
Derived class:
public class Car : Vehicle
{
private readonly ICleanVehicle _cleanVehicle;
public Car(ICleanVehicle cleanVehicle) : base(cleanVehicle)
{
_cleanVehicle = cleanVehicle;
}
}
This way you have one single constructor defining the dependencies that the derived classes require. The derived classes will then call the constructor of the base class.

Inheritance in Specflow test steps cause Ambiguous Steps

I've read that using inheritance is not possible when using Specflow, which makes sense most of the time. However, I've run across a situation that seems to require the proper the use of inheritance. Here are my classes:
Base Class:
public class StepBaseClass
{
protected readonly ScenarioContext scenarioContext;
public StepBaseClass(ScenarioContext scenarioContext)
{
this.scenarioContext = scenarioContext;
}
}
First Inherited Class:
[Binding]
public class StudioEnterpriseImportConnectorSteps:StepBaseClass
{
public StudioEnterpriseImportConnectorSteps(ScenarioContext scenarioContext) :base(scenarioContext)
{
}
[Given(#"I have a data record that I want to send to the import service")]
public void GivenIHaveADataRecordThatIWantToSendToTheImportService()
{
scenarioContext.Pending();
}
[When(#"I send the information to an invalid URL")]
public void WhenISendTheInformationToAnInvalidURL()
{
scenarioContext.Pending();
}
[Then(#"an error should be generated")]
public void ThenAnErrorShouldBeGenerated()
{
scenarioContext.Pending();
}
}
2nd inherited class:
[Binding]
public class SitemapSteps:StepBaseClass
{
public SitemapSteps(ScenarioContext scenarioContext):base(scenarioContext)
{
}
[When(#"I visit the URL (.*)")]
public void WhenIVisitTheSitemapURL(string URL)
{
scenarioContext.Add("result", TestUtilities.GetResponseCode(URL));
scenarioContext.Add("response", TestUtilities.GetResponseBody(URL));
}
[Then(#"the response code should be (.*)")]
public void ThenTheResponseCodeShouldBe(string responseCode)
{
HttpStatusCode result = scenarioContext.Get<HttpStatusCode>("result");
Assert.Equal(responseCode, result.ToString());
}
}
As you can see, the only thing that I'm inheriting the the scenarioContext, which is something that I need to do in order to write multi-threaded tests. So instead of repeating this piece of code for each of my classes, I would like to be able to inherit from a base class. What is the proper method of initializing that variable so that I can use it in each of my derived classes?
The proper way depends as always on your individual situaion.
I recommend always to not use base classes and use context injection everywhere. The small number of code that is repeated in the constructor is a small price for a good separation and splitting of your bindings and their implementation.
To get more info about this topic, Gaspar Nagy wrote a nice blog article about the pros and cons of step base classes in SpecFlow:
http://gasparnagy.com/2017/02/specflow-tips-baseclass-or-context-injection/
After initializing my Dependency Injection in the Specflow Test hooks, I would have a class called ApplicationContext with a static resolve method which would return me my ScenarioContext instance like so:
public class ApplicationContext
{
public static T Resolve<T>() where T: class
{
return container.GetInstance<T>();
}
}
Then in my steps class, I would resolve the ScenarioContext like this:
scenarioContext = (ScenarioContext)ApplicationContext.Resolve<IScenarioContext>();

Casting Generic to abstract base - covariance

The code below gives compile time error:
Error 170 Cannot convert type 'Tests.ChangeListener' to 'Tests.BaseListener'
How do I get this to compile?
namespace Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void ShouldCompile()
{
BaseListener<IChange> listener = (BaseListener<IChange>)new ChangeListener();
}
}
public interface IChange
{
}
public interface ISpecificChange : IChange
{
}
public abstract class BaseListener<T>
where T : IChange
{
}
public class ChangeListener : BaseListener<ISpecificChange>
{
}
}
Since you can't do contravariance or covaraiance (ie in and out) on an abstract class you'll probably want an interface for your listener. Modifying the above to look like this allows it to compile (note entities not mentioned remain the same as the original code - attributes stripped to save me needing to import references while testing):
public class UnitTest1
{
public void ShouldCompile()
{
IListener<IChange> listener = new ChangeListener();
}
}
public interface IListener<out T> {}
public abstract class BaseListener<T> : IListener<T>
where T : IChange
{
}
This is obviously adding in a step that you don't currently have and may not be able to use for whatever reasons but it is the simplest way to get the code compiling and I think do what you want.

Using StructureMap with derived interfaces

I have an object hierarchy similar to the following:
interface IVideoStream { }
abstract class VideoStream : IVideoStream { }
interface IVideoStreamTypeA : IVideoStream { /* Specific for type A */ }
interface IVideoStreamTypeB : IVideoStream { /* Specific for type B */ }
class VideoStreamTypeA : IVideoStreamTypeA { }
class VideoStreamTypeB : IVideoStreamTypeB { }
There should be a single instance of both VideoStreamTypeA and VideoStreamTypeB, as they wrap some resources. Some classes consume IVideoStreamTypeA or IVideoStreamTypeB directly, and some classes take a list of IVideoStream.
The register code looks like this:
class MyRegistry: Registry
{
public MyRegistry()
{
For<IVideoStreamTypeA>().Use<VideoStreamTypeA>()
.Ctor<>() // Specific initialization
For<IVideoStreamTypeB>().Use<VideoStreamTypeB>()
.Ctor<>() // Specific initialization
For<IVideoStreamTypeA>().Singleton();
For<IVideoStreamTypeB>().Singleton();
}
}
Finally, there are some classes that take a list of IVideoStream:
class MyClass
{
public MyClass(IEnumerable<IVideoStream> streams) { }
}
With the current registry code, the "streams" parameter is empty. How do I get StructureMap to inject the two instances from above?
My current approach is to use the following:
Forward<IVideoStreamTypeA, IVideoStream>();
Forward<IVideoStreamTypeB, IVideoStream>();
But I'm not sure it's the best solution

Categories