I understand the whole concept behind inversion of control, but struggle to figure out where an IoC container comes in and how it may help.
Here's an example. Let's say we have the following interfaces ...
public interface IWarrior
{
string Name { get; }
IWeapon Weapon { get; }
void EquipWeapon(IWeapon weapon);
void Attack(ITarget target);
void DoVictoryDance();
}
public interface IWeapon
{
int AttackPower { get; }
}
public interface ITarget
{
int Health { get; }
int ArmorValue { get; }
int ReceiveAttack(int damage);
}
A IWarrior base class ...
public abstract class BaseWarrior : IWarrior
{
private static readonly Random Random = new Random();
protected BaseWarrior(string name, IWeapon weapon)
{
Name = name;
Weapon = weapon;
}
public string Name { get; }
public IWeapon Weapon { get; private set; }
public virtual void Attack(ITarget target)
{
var attackValue = Random.Next(0, Weapon.AttackPower + 1);
var damageDone = target.ReceiveAttack(attackValue);
Console.WriteLine($"{Name} did {damageDone} to {target.GetType().Name}");
if (target.Health <= 0)
DoVictoryDance();
}
public virtual void EquipWeapon(IWeapon weapon)
{
Weapon = weapon;
Console.WriteLine($"{Name} equips {weapon.GetType().Name}");
}
public abstract void DoVictoryDance();
}
The concrete warriors types ...
public class Samurai : BaseWarrior
{
public Samurai(string name, IWeapon weapon) : base(name, weapon)
{
}
public override void DoVictoryDance()
{
Console.WriteLine($"{Name} dances on top of the corpses of his foes.");
}
}
public class ChuckNorris : BaseWarrior
{
public ChuckNorris() : base("Chuck Norris", null)
{
}
public override void Attack(ITarget target)
{
var targetName = target.GetType().Name;
Console.WriteLine($"Chuck Norris stares at {targetName}. {targetName} collapses on the floor, dead. {targetName} never saw Chuck Norris.");
DoVictoryDance();
}
public override void EquipWeapon(IWeapon weapon)
{
Console.WriteLine("Chuck Norris needs no weapons you fool!");
}
public override void DoVictoryDance()
{
Console.WriteLine("Chuck Norris doesn't dance. He stares at you until you do it for him.");
}
}
The following weapons...
public class Sword : IWeapon
{
public int AttackPower => 10;
}
public class CrossBow : IWeapon
{
public int AttackPower => 15;
}
And finally a basic enemy:
public class Bear : ITarget
{
public int Health { get; private set; } = 100;
public int ArmorValue => 2;
public int ReceiveAttack(int damage)
{
var damageTaken = damage - ArmorValue;
if (damageTaken > 0)
Health -= damageTaken;
return damageTaken;
}
}
It's clear to me what inversion of control here is. My main class needs not know the concrete type of IWarrior, IWarrior never knows the concrete type of IWeapon or ITarget.
So this allows me to do something like ...
ITarget target = new Bear();
IWarrior warrior = new ChuckNorris();
warrior.Attack(target);
or ...
ITarget target = new Bear()
IWarrior warrior = new Samurai("Ben", new Sword());
warrior.Attack(target);
And I can see how it would be easier to have a container that just stores my objects so I don't "lose track of them" (don't want a lot of swords or weapons flying around for example, also those could be singletons).
Examples I've seen of IoC containers show something similar to this:
IocContainer container = new IocContainer();
container.Bind<IWarrior>().To<Samurai>();
container.Bind<IWeapon>().To<Sword>();
container.Bind<ITarget>().To<Bear>();
and then doing something like...
ITarget target = container.Get<ITarget>();
IWarrior warrior = container.Get<IWarrior>();
warrior.Attack(target);
But now I'm basically saying that my IWarrior is always a Samurai, that my IWeapon is always a Sword and that my ITarget is always a Bear.
That's not really what I wanted! I want to be able to create different IWarrior types with different IWeapon combinations and attacking a multitude of ITargets!
Maybe I'm misunderstanding something basic about how an IoC container works, but I have seen a few videos about them (using multiple libraries) and they all appear to basically say when I want "something" implementing interface XX, find in your container an object of concrete type YY. If you don't have one there yet, create one, save it, and send it back to me.
Can someone explain what the advantages of an IoC container are, give real examples of how it works and how one can preserve choice (by not limiting a IWarrior to Samurai as above for example)?
Hi guys :) I am learning C# and would like some help about inherited member/field. I have a class called Car, suppose with only one engine. However, recently I want to make a race car with 2 or more engines. The field "my_Engine" inherited from parent class seems not appropriate and I leave it to null.
Problem 1 Replace_Engine(Engine new_Engine) no longer usable in Race_Car
Problem 2 Replace_Engine(Engine target, Engine new_Engine) can only be used after an explicit cast to Race_Car.
I have quite a number of subclass of Car. How can I solve these? Do I need to rewrite all of them?
Should I rewrite them all, does replacing my_Engine to an array good enough? But not all cars have more than 1 engine... using an array seems strange. I am quite confused here.
Appreciated all your help :)
public class Car
{
//can store only one engine
protected Engine my_Engine;
//Changed to virtual to let Race_Car to override
public virtual float Get_Horse_Power()
{
return my_Engine.max_Power;
}
//Changed to virtual to let Race_Car to override
public virtual void Replace_Engine(Engine new_Engine)
{
my_Engine = new_Engine;
}
}
public class Race_Car : Car
{
protected Engine[] my_Engines;
public override float Get_Horse_Power()
{
float result=0;
for(int i = 0; i <my_Engines.Length;i++)
{
result+=my_Engines.max_Power;
}
return result;
}
//Don't know which engine need to be replaced
public override void Replace_Engine(Engine new_Engine)
{
throw new System.NotImplementedException();
}
//Created a overloading method but need an explicit cast to call
public void Replace_Engine(Engine target, Engine new_Engine)
{
for(int i = 0; i <my_Engines.Length;i++)
{
if(my_Engines[i]==target)
{
my_Engines[i]= new_Engine;
return;
}
}
}
}
The base class here assumes in the API that there is only a single engine, so yes: this will be awkward to use with types that don't adhere to that API. You could perhaps do something like:
public virtual int EngineCount => 1;
public virtual void ReplaceEngine(Engine newEngine, int engineIndex = 0)
{
if(engineIndex != 0) throw new ArgumentOutOfRangeException(nameof(engineIndex));
_engine = newEngine;
}
and:
public override int EngineCount => 2;
public void override ReplaceEngine(Engine newEngine, int engineIndex = 0)
{
switch(engineIndex)
{
case 1: _secondEngine = newEngine; break;
default: base.ReplaceEngine(newEngine, engineIndex); break;
}
}
One possible way to go about this is to make the concept of an Engine abstract and let the fact that you may have more than one physical unit serving the power be of no consequence to the original design.
You start with an abstract class that represents an engine:
public abstract class Engine
{
public Engine()
{
}
internal abstract float max_Power { get; }
}
You then implement the two flavors of engines. A simple one:
public class SimpleEngine : Engine
{
private float _maxPower;
public SimpleEngine(float maxPower)
{
_maxPower = maxPower;
}
internal override float MaxPower
{
get { return _maxPower; }
}
}
And a composite one:
public class CompositeEngine : Engine
{
private List<Engine> _engines = new List<Engine>();
public CompositeEngine(params Engine[] engines)
{
_engines.AddRange(engines);
}
internal override float MaxPower
{
get { return _engines.Sum(e => e.MaxPower); }
}
}
Usage:
var engine = new CompositeEngine(new SimpleEngine(5), new SimpleEngine(4), new SimpleEngine(3));
var car = new Car();
car.Replace_Engine(engine);
var value = car.Get_Horse_Power();
Output:
value = 12
My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.
TL;DR - I'm looking for xUnit's equivalent of MSTest's AssemblyInitialize (aka the ONE feature it has that I like).
Specifically I'm looking for it because I have some Selenium smoke tests which I would like to be able to run with no other dependencies. I have a Fixture that will launch IisExpress for me and kill it on disposal. But doing this before every test hugely bloats runtime.
I would like to trigger this code once at the start of testing, and dispose of it (shutting down the process) at the end. How could I go about doing that?
Even if I can get programmatic access to something like "how many tests are currently being run" I can figure something out.
As of Nov 2015 xUnit 2 is out, so there is a canonical way to share features between tests. It is documented here.
Basically you'll need to create a class doing the fixture:
public class DatabaseFixture : IDisposable
{
public DatabaseFixture()
{
Db = new SqlConnection("MyConnectionString");
// ... initialize data in the test database ...
}
public void Dispose()
{
// ... clean up test data from the database ...
}
public SqlConnection Db { get; private set; }
}
A dummy class bearing the CollectionDefinition attribute.
This class allows Xunit to create a test collection, and will use the given fixture for all test classes of the collection.
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
// 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.
}
Then you need to add the collection name over all your test classes.
The test classes can receive the fixture through the constructor.
[Collection("Database collection")]
public class DatabaseTestClass1
{
DatabaseFixture fixture;
public DatabaseTestClass1(DatabaseFixture fixture)
{
this.fixture = fixture;
}
}
It's a bit more verbose than MsTests AssemblyInitialize since you have to declare on each test class which test collection it belongs, but it's also more modulable (and with MsTests you still need to put a TestClass on your classes)
Note: the samples have been taken from the documentation.
To execute code on assembly initialize, then one can do this (Tested with xUnit 2.3.1)
using Xunit.Abstractions;
using Xunit.Sdk;
[assembly: Xunit.TestFramework("MyNamespace.MyClassName", "MyAssemblyName")]
namespace MyNamespace
{
public class MyClassName : XunitTestFramework
{
public MyClassName(IMessageSink messageSink)
:base(messageSink)
{
// Place initialization code here
}
public new void Dispose()
{
// Place tear down code here
base.Dispose();
}
}
}
See also https://github.com/xunit/samples.xunit/tree/master/AssemblyFixtureExample
Create a static field and implement a finalizer.
You can use the fact that xUnit creates an AppDomain to run your test assembly and unloads it when it's finished. Unloading the app domain will cause the finalizer to run.
I am using this method to start and stop IISExpress.
public sealed class ExampleFixture
{
public static ExampleFixture Current = new ExampleFixture();
private ExampleFixture()
{
// Run at start
}
~ExampleFixture()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize(this);
// Run at end
}
}
Edit: Access the fixture using ExampleFixture.Current in your tests.
It's not possible to do in the framework today. This is a feature planned for 2.0.
In order to make this work before 2.0, it would require you to perform significant re-architecture on the framework, or write your own runners that recognized your own special attributes.
I use AssemblyFixture (NuGet).
What it does is it provides an IAssemblyFixture<T> interface that is replacing any IClassFixture<T> where you want the object's lifetime to be as the testing assembly.
Example:
public class Singleton { }
public class TestClass1 : IAssemblyFixture<Singleton>
{
readonly Singletone _Singletone;
public TestClass1(Singleton singleton)
{
_Singleton = singleton;
}
[Fact]
public void Test1()
{
//use singleton
}
}
public class TestClass2 : IAssemblyFixture<Singleton>
{
readonly Singletone _Singletone;
public TestClass2(Singleton singleton)
{
//same singleton instance of TestClass1
_Singleton = singleton;
}
[Fact]
public void Test2()
{
//use singleton
}
}
I was quite annoyed for not having the option to execute things at the end of all the xUnit tests. Some of the options here are not as great, as they involve changing all your tests or putting them under one collection (meaning they get executed synchronously). But Rolf Kristensen's answer gave me the needed information to get to this code. It's a bit long, but you only need to add it into your test project, no other code changes necessary:
using Siderite.Tests;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
[assembly: TestFramework(
SideriteTestFramework.TypeName,
SideriteTestFramework.AssemblyName)]
namespace Siderite.Tests
{
public class SideriteTestFramework : ITestFramework
{
public const string TypeName = "Siderite.Tests.SideriteTestFramework";
public const string AssemblyName = "Siderite.Tests";
private readonly XunitTestFramework _innerFramework;
public SideriteTestFramework(IMessageSink messageSink)
{
_innerFramework = new XunitTestFramework(messageSink);
}
public ISourceInformationProvider SourceInformationProvider
{
set
{
_innerFramework.SourceInformationProvider = value;
}
}
public void Dispose()
{
_innerFramework.Dispose();
}
public ITestFrameworkDiscoverer GetDiscoverer(IAssemblyInfo assembly)
{
return _innerFramework.GetDiscoverer(assembly);
}
public ITestFrameworkExecutor GetExecutor(AssemblyName assemblyName)
{
var executor = _innerFramework.GetExecutor(assemblyName);
return new SideriteTestExecutor(executor);
}
private class SideriteTestExecutor : ITestFrameworkExecutor
{
private readonly ITestFrameworkExecutor _executor;
private IEnumerable<ITestCase> _testCases;
public SideriteTestExecutor(ITestFrameworkExecutor executor)
{
this._executor = executor;
}
public ITestCase Deserialize(string value)
{
return _executor.Deserialize(value);
}
public void Dispose()
{
_executor.Dispose();
}
public void RunAll(IMessageSink executionMessageSink, ITestFrameworkDiscoveryOptions discoveryOptions, ITestFrameworkExecutionOptions executionOptions)
{
_executor.RunAll(executionMessageSink, discoveryOptions, executionOptions);
}
public void RunTests(IEnumerable<ITestCase> testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions)
{
_testCases = testCases;
_executor.RunTests(testCases, new SpySink(executionMessageSink, this), executionOptions);
}
internal void Finished(TestAssemblyFinished executionFinished)
{
// do something with the run test cases in _testcases and the number of failed and skipped tests in executionFinished
}
}
private class SpySink : IMessageSink
{
private readonly IMessageSink _executionMessageSink;
private readonly SideriteTestExecutor _testExecutor;
public SpySink(IMessageSink executionMessageSink, SideriteTestExecutor testExecutor)
{
this._executionMessageSink = executionMessageSink;
_testExecutor = testExecutor;
}
public bool OnMessage(IMessageSinkMessage message)
{
var result = _executionMessageSink.OnMessage(message);
if (message is TestAssemblyFinished executionFinished)
{
_testExecutor.Finished(executionFinished);
}
return result;
}
}
}
}
The highlights:
assembly: TestFramework instructs xUnit to use your framework, which
proxies to the default one
SideriteTestFramework also wraps the executor into a custom class
that then wraps the message sink
in the end, the Finished method is executed, with the list of tests
run and the result from the xUnit message
More work could be done here. If you want to execute stuff without caring about the tests run, you could inherit from XunitTestFramework and just wrap the message sink.
You can use IUseFixture interface to make this happen. Also all of your test must inherit TestBase class. You can also use OneTimeFixture directly from your test.
public class TestBase : IUseFixture<OneTimeFixture<ApplicationFixture>>
{
protected ApplicationFixture Application;
public void SetFixture(OneTimeFixture<ApplicationFixture> data)
{
this.Application = data.Fixture;
}
}
public class ApplicationFixture : IDisposable
{
public ApplicationFixture()
{
// This code run only one time
}
public void Dispose()
{
// Here is run only one time too
}
}
public class OneTimeFixture<TFixture> where TFixture : new()
{
// This value does not share between each generic type
private static readonly TFixture sharedFixture;
static OneTimeFixture()
{
// Constructor will call one time for each generic type
sharedFixture = new TFixture();
var disposable = sharedFixture as IDisposable;
if (disposable != null)
{
AppDomain.CurrentDomain.DomainUnload += (sender, args) => disposable.Dispose();
}
}
public OneTimeFixture()
{
this.Fixture = sharedFixture;
}
public TFixture Fixture { get; private set; }
}
EDIT: Fix the problem that new fixture create for each test class.
Does your build tool provide such a feature?
In the Java world, when using Maven as a build tool, we use the appropriate phases of the build lifecycle. E.g. in your case (acceptance tests with Selenium-like tools), one can make good use of the pre-integration-test and post-integration-test phases to start/stop a webapp before/after one's integration-tests.
I'm pretty sure the same mechanism can be set up in your environment.
The method described by Jared Kells
does not work under Net Core, because, well it is not guaranteed that finalizers will be called. And, in fact, it is not called for the code above. Please, see:
Why does the Finalize/Destructor example not work in .NET Core?
https://github.com/dotnet/runtime/issues/16028
https://github.com/dotnet/runtime/issues/17836
https://github.com/dotnet/runtime/issues/24623
So, based on the great answer above, here is what I ended up doing (replace saving to file as necessary):
public class DatabaseCommandInterceptor : IDbCommandInterceptor
{
private static ConcurrentDictionary<DbCommand, DateTime> StartTime { get; } = new();
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) => Log(command, interceptionContext);
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) => Log(command, interceptionContext);
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) => Log(command, interceptionContext);
private static void Log<T>(DbCommand command, DbCommandInterceptionContext<T> interceptionContext)
{
var parameters = new StringBuilder();
foreach (DbParameter param in command.Parameters)
{
if (parameters.Length > 0) parameters.Append(", ");
parameters.Append($"{param.ParameterName}:{param.DbType} = {param.Value}");
}
var data = new DatabaseCommandInterceptorData
{
CommandText = command.CommandText,
CommandType = $"{command.CommandType}",
Parameters = $"{parameters}",
Duration = StartTime.TryRemove(command, out var startTime) ? DateTime.Now - startTime : TimeSpan.Zero,
Exception = interceptionContext.Exception,
};
DbInterceptorFixture.Current.LogDatabaseCall(data);
}
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) => OnStart(command);
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) => OnStart(command);
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) => OnStart(command);
private static void OnStart(DbCommand command) => StartTime.TryAdd(command, DateTime.Now);
}
public class DatabaseCommandInterceptorData
{
public string CommandText { get; set; }
public string CommandType { get; set; }
public string Parameters { get; set; }
public TimeSpan Duration { get; set; }
public Exception Exception { get; set; }
}
/// <summary>
/// All times are in milliseconds.
/// </summary>
public record DatabaseCommandStatisticalData
{
public string CommandText { get; }
public int CallCount { get; init; }
public int ExceptionCount { get; init; }
public double Min { get; init; }
public double Max { get; init; }
public double Mean { get; init; }
public double StdDev { get; init; }
public DatabaseCommandStatisticalData(string commandText)
{
CommandText = commandText;
CallCount = 0;
ExceptionCount = 0;
Min = 0;
Max = 0;
Mean = 0;
StdDev = 0;
}
/// <summary>
/// Calculates k-th moment for n + 1 values: M_k(n + 1)
/// based on the values of k, n, mkn = M_k(N), and x(n + 1).
/// The sample adjustment (replacement of n -> (n - 1)) is NOT performed here
/// because it is not needed for this function.
/// Note that k-th moment for a vector x will be calculated in Wolfram as follows:
/// Sum[x[[i]]^k, {i, 1, n}] / n
/// </summary>
private static double MknPlus1(int k, int n, double mkn, double xnp1) =>
(n / (n + 1.0)) * (mkn + (1.0 / n) * Math.Pow(xnp1, k));
public DatabaseCommandStatisticalData Updated(DatabaseCommandInterceptorData data) =>
CallCount == 0
? this with
{
CallCount = 1,
ExceptionCount = data.Exception == null ? 0 : 1,
Min = data.Duration.TotalMilliseconds,
Max = data.Duration.TotalMilliseconds,
Mean = data.Duration.TotalMilliseconds,
StdDev = 0.0,
}
: this with
{
CallCount = CallCount + 1,
ExceptionCount = ExceptionCount + (data.Exception == null ? 0 : 1),
Min = Math.Min(Min, data.Duration.TotalMilliseconds),
Max = Math.Max(Max, data.Duration.TotalMilliseconds),
Mean = MknPlus1(1, CallCount, Mean, data.Duration.TotalMilliseconds),
StdDev = Math.Sqrt(
MknPlus1(2, CallCount, Math.Pow(StdDev, 2) + Math.Pow(Mean, 2), data.Duration.TotalMilliseconds)
- Math.Pow(MknPlus1(1, CallCount, Mean, data.Duration.TotalMilliseconds), 2)),
};
public static string Header { get; } =
string.Join(TextDelimiter.VerticalBarDelimiter.Key,
new[]
{
nameof(CommandText),
nameof(CallCount),
nameof(ExceptionCount),
nameof(Min),
nameof(Max),
nameof(Mean),
nameof(StdDev),
});
public override string ToString() =>
string.Join(TextDelimiter.VerticalBarDelimiter.Key,
new[]
{
$"\"{CommandText.Replace("\"", "\"\"")}\"",
$"{CallCount}",
$"{ExceptionCount}",
$"{Min}",
$"{Max}",
$"{Mean}",
$"{StdDev}",
});
}
public class DbInterceptorFixture
{
public static readonly DbInterceptorFixture Current = new();
private bool _disposedValue;
private ConcurrentDictionary<string, DatabaseCommandStatisticalData> DatabaseCommandData { get; } = new();
private static IMasterLogger Logger { get; } = new MasterLogger(typeof(DbInterceptorFixture));
/// <summary>
/// Will run once at start up.
/// </summary>
private DbInterceptorFixture()
{
AssemblyLoadContext.Default.Unloading += Unloading;
}
/// <summary>
/// A dummy method to call in order to ensure that static constructor is called
/// at some more or less controlled time.
/// </summary>
public void Ping()
{
}
public void LogDatabaseCall(DatabaseCommandInterceptorData data) =>
DatabaseCommandData.AddOrUpdate(
data.CommandText,
_ => new DatabaseCommandStatisticalData(data.CommandText).Updated(data),
(_, d) => d.Updated(data));
private void Unloading(AssemblyLoadContext context)
{
if (_disposedValue) return;
GC.SuppressFinalize(this);
_disposedValue = true;
SaveData();
}
private void SaveData()
{
try
{
File.WriteAllLines(
#"C:\Temp\Test.txt",
DatabaseCommandData
.Select(e => $"{e.Value}")
.Prepend(DatabaseCommandStatisticalData.Header));
}
catch (Exception e)
{
Logger.LogError(e);
}
}
}
and then register DatabaseCommandInterceptor once somewhere in the tests:
DbInterception.Add(new DatabaseCommandInterceptor());
I also prefer calling DbInterceptorFixture.Current.Ping() in the base test class, though I don't think that this is needed.
The interface IMasterLogger is just a strongly typed wrapper around log4net, so just replace it with your favorite one.
The value of TextDelimiter.VerticalBarDelimiter.Key is just '|' and it sits in what we call a closed set.
PS If I screwed up with statistics, please, comment and I will update the answer.
Just use the static constructor, that's all you need to do, it runs just once.
I have a "meter" class. One property of "meter" is another class called "production".
I need to access to a property of meter class (power rating) from production class by reference. The powerRating is not known at the instantiation of Meter.
How can I do that?
public class Meter
{
private int _powerRating = 0;
private Production _production;
public Meter()
{
_production = new Production();
}
}
Store a reference to the meter instance as a member in Production:
public class Production {
//The other members, properties etc...
private Meter m;
Production(Meter m) {
this.m = m;
}
}
And then in the Meter-class:
public class Meter
{
private int _powerRating = 0;
private Production _production;
public Meter()
{
_production = new Production(this);
}
}
Also note that you need to implement an accessor method/property so that the Production class can actually access the powerRating member of the Meter class.
I wouldn't reference the parent directly in the child objects. In my opinion the childs shouldn't know anything about the parents. This will limits the flexibility!
I would solve this with events/handlers.
public class Meter
{
private int _powerRating = 0;
private Production _production;
public Meter()
{
_production = new Production();
_production.OnRequestPowerRating += new Func<int>(delegate { return _powerRating; });
_production.DoSomething();
}
}
public class Production
{
protected int RequestPowerRating()
{
if (OnRequestPowerRating == null)
throw new Exception("OnRequestPowerRating handler is not assigned");
return OnRequestPowerRating();
}
public void DoSomething()
{
int powerRating = RequestPowerRating();
Debug.WriteLine("The parents powerrating is :" + powerRating);
}
public Func<int> OnRequestPowerRating;
}
In this case I solved it with the Func<> generic, but can be done with 'normal' functions.
This why the child(Production) is totally independent from it's parent(Meter).
But! If there are too many events/handlers or you just want to pass a parent object, i would solve it with an interface:
public interface IMeter
{
int PowerRating { get; }
}
public class Meter : IMeter
{
private int _powerRating = 0;
private Production _production;
public Meter()
{
_production = new Production(this);
_production.DoSomething();
}
public int PowerRating { get { return _powerRating; } }
}
public class Production
{
private IMeter _meter;
public Production(IMeter meter)
{
_meter = meter;
}
public void DoSomething()
{
Debug.WriteLine("The parents powerrating is :" + _meter.PowerRating);
}
}
This looks pretty much the same as the solution mentions, but the interface could be defined in another assembly and can be implemented by more than 1 class.
Regards,
Jeroen van Langen.
You would need to add a property to your Production class and set it to point back at its parent, this doesn't exist by default.
Why not change the constructor on Production to let you pass in a reference at construction time:
public class Meter
{
private int _powerRating = 0;
private Production _production;
public Meter()
{
_production = new Production(this);
}
}
In the Production constructor you can assign this to a private field or a property. Then Production will always have access to is parent.
You could maybe add a method to your Production object called 'SetPowerRating(int)' which sets a property in Production, and call this in your Meter object before using the property in the Production object?
I would give the parent an ID, and store the parentID in the child object, so that you can pull information about the parent as needed without creating a parent-owns-child/child-owns-parent loop.
something like this:
public int PowerRating
{
get { return base.PowerRating; } // if power inherits from meter...
}