MongoDB with C# driver 2.0 is frozen - c#

I am running a C# app with MongoDB 2.0 driver and ran into the following error when I ran all my tests:
System.InvalidOperationException : Class map for <TopClassName> has been frozen and no further changes are allowed.
System.AggregateException : One or more errors occurred. ----> MongoDB.Bson.BsonException : Unable to find a matching member to provide the value for parameter 'inBed'
However, running every single test one at a time gives no errors.
So for some reason the class map is frozen...
Here is what I have
(P.S, if you spot something that is way off, let me know):
A hierarchy with 3 abstract classes and one concrete class:
public abstract class BaseEvent
{
[BsonId]
public Guid Id;
public List<int> Data;
public dynamic Condition;
public string TimeStamp;
[BsonConstructor]
protected BaseEvent(List<int> data, dynamic condition)
{
Data = data;
Condition = condition;
TimeStamp = DateTime.Now.ToString();
Id = Guid.NewGuid();
}
}
public abstract class Basic : BaseEvent
{
[BsonConstructor]
protected Basic(List<int> data, bool condition) : base(data, condition)
{}
}
public abstract class BedEvent : Basic
{
[BsonConstructor]
protected BedEvent(List<int> data, bool inBed) : base(data, inBed)
{}
}
public class DummyBed : BedEvent
{
[BsonConstructor]
public DummyBed(List<int> data, bool inBed) : base(data, inBed)
{
RegisterHelper.RegisterNewClass(this);
}
}
The RegisterHelper is a singleton that is kept alive, more on that a bit down.
The constructor of my app will register the top class BaseEvent:
var baseEvent = BsonClassMap.RegisterClassMap<BaseEvent>(cm =>
{
cm.SetIsRootClass(true);
cm.MapMember(c => c.Data);
cm.MapMember(c => c.Condition);
cm.MapMember(c => c.TimeStamp);
cm.MapIdMember(c => c.Id).SetIdGenerator(GuidGenerator.Instance);
});
RegisterHelper.ClassRegister.Add(baseEvent);
For each concrete class, as the DummyBed, I call a homebrewed (and likely to be the cause of the problem) register method.
This method looks at all the baseclasses and, if not found on a list, adds them recursively to all classes above them self, much like this:
public static void RegisterNewClass<T>(T theObject)
{
...
if (!lvl3Found)
{
var lvl3Map = new BsonClassMap(lvl3Type); //lvl3Type is a System.Type
lvl3Map.SetDiscriminator(lvl3Type.Name);
ClassRegister.Add(lvl3Map);
BsonClassMap.RegisterClassMap(lvl3Map);
lvl4Map.AddKnownType(lvl3Type);
}
...
}
Full class can be found here.
Running tests:
[TestFixture]
public class InsertEventIntoDatabaseTest
{
private EventDatabase _eventDatabase;
[SetUp]
public void Setup()
{
_eventDatabase = new EventDatabase();
_eventDatabase.EmptyDatabase(); //Clean slate each time
}
[TearDown]
public void TearDown()
{
_eventDatabase = null;
}
[Test]
public void GetSubTypeDocument_FindDummyBed_Success()
{
var bed = new DummyBed(new List<int>() { 1, 2, 3}, true);
_eventDatabase.InsertEventInDatabase(bed);
var doc = _eventDatabase.GetDocument();
_eventDatabase.GetSubTypeDocument(typeof(DummyBed));
Assert.That(doc, Is.TypeOf<DummyBed>()); //Great success
}
[Test]
public void FindTypeEvents_FindTwo_Succes()
{
var data = new List<int>() { 1, 2, 3 };
var bed1 = new DummyBed(data, true);
var bed2 = new DummyBed(data, true);
_eventDatabase.InsertEventInDatabase(bed1);
_eventDatabase.InsertEventInDatabase(bed2);
var foundEvents = _eventDatabase.FindTypeEvents(typeof(BedEvent));
Assert.That(foundEvents.Count, Is.EqualTo(2)); // Frozen
}
...
}
However - running each test by it self gives only green check marks. So it is down to how fast it can handle events.
The database is cleared each time a new test is run, so there should be no operations running.
The methods called should wait until they finish:
public void InsertEventInDatabase(BaseEvent inputBaseEvent)
{
inputBaseEvent.Condition = (inputBaseEvent.Condition is bool ? (inputBaseEvent.Condition == true ? 100 : 0) : inputBaseEvent.Condition);
var collection = _database.GetCollection<dynamic>(DatabaseCollection);
collection.InsertOneAsync(inputBaseEvent).Wait(); //Should wait, right?
}
public List<BaseEvent> FindTypeEvents(Type typeFilter)
{
var name = _database.GetCollection<BaseEvent>(DatabaseCollection)
.Find(x => x.Id != Guid.Empty)
.ToListAsync();
return name.Result; //Should wait here as well, right?
}
Any suggestions on where to look for the cause of the problem?
It is quite limit with information on the interwebs after the April update of the C# driver, so any suggestions are welcome.

So, the error did not go away, but apparently did not affect the system if ignored.
I believe this is a mistake, but I have 34 green unit tests now, and the system runs nicely in release mode.
public static void RegisterNewClass<T>(T theObject)
{
...
if (!lvl3Found)
{
try
{
lvl3Map.SetDiscriminator(lvl3Type.Name);
BsonClassMap.RegisterClassMap(lvl3Map);
lvl4Map.AddKnownType(lvl3Type);
}
catch (Exception e)
{
Console.WriteLine("Level 3 adding went wrong!");
Console.WriteLine(e.Message);
}
}
...
}
I can't say why it actually works.
What triggers the exception is the line lvl4Map.AddKnownType(lvl3Type) stating lvl4Map is frozen.
But as said, the test still runs with a green flag, so I am not sure it is a big deal.
It could be a bug.

Related

Moq parent method being called in child class

I have a base class with a protected method that's being called in a public method in the child class I want to test. I'm failing to find a way to moq the base protected method for easier testing in child class.
public class MyBaseClass
{
protected virtual bool MyMethod(int number)
{
return number == 1;
}
}
public class MyChildClass : MyBaseClass
{
public bool DoSomething(int number)
{
return MyMethod(number);
}
}
[TestFixture]
public class MyChildClassTests
{
[Test]
public void Expected_Returns_False_WhenPassed_1()
{
var myChildClass = new MyChildClass();
// How do I mock MyMethod used in myBaseClass here?
// var mock = new Mock<MyBaseClass>();
// mock.Protected().Setup<bool>("MyMethod", ItExpr.IsAny<int>()).Returns(false);
// The above mock is correct, but it's in a different instance object than myBaseClass
var result = myChildClass.DoSomething();
Assert.AreEqual(false, result);
}
}
I can't change the classes to have a better architecture and I must do the best I can to implement unit test for DoSomething(), what I did so far is mock and prepare all the data that method uses, but since it's in another class I'd love my MyChildClassTests to not do all that and just limit to test DoSomething().
I've read about partial mocking and a whole lot of other questions and answers and I can't get it to work right.
I appreciate any suggestions!
Edit: Forgot to put public in all the classes, in my real world case, they are public.
class MyChildClassTests
{
[Test]
public void Expected_Returns_False_WhenPassed_1()
{
var myChildClass = new FakeChildClass();
var result = myChildClass.DoSomething(1);
Assert.AreEqual(false, result);
}
}
public class FakeChildClass: MyChildClass
{
protected override bool MyMethod(int number)
{
return number == 1;
}
}
First of all, ensure your classes are public.
Moq will complain about not being able to proxy into them if they're not.
public class MyBaseClass
{
public virtual bool MyMethod(int number)
{
return number == 1;
}
}
public class MyChildClass : MyBaseClass
{
public bool DoSomething(int number)
{
return MyMethod(number);
}
}
Next, make your base class method public. You won't be able to set it up unless you do.
After that, create a mock of the child object and mock the parent method.
var mockChild = new Mock<MyChildClass>(){CallBase = true};
mockChild.Setup(x => x.MyMethod(It.IsAny<int>())).Returns(false);
Pull your result.... result will return false even though the actual implementation would have returned true with 1 as a parameter.
var result = mockChild.Object.DoSomething(1);
When calling the DoSomething method, you'll actually enter the real implementation of that (put a breakpoint on if you don't believe me!) - but the mocked version of MyMethod will kick in.
Thanks all for your replies, gathering all I was able to get the actual answer to my use case:
Without changing MyBaseClass and MyChildClass:
public class MyBaseClass
{
protected virtual bool MyMethod(int number)
{
return number == 1;
}
}
public class MyChildClass : MyBaseClass
{
public bool DoSomething(int number)
{
return MyMethod(number);
}
}
I was able to mock the protected method and save me a LOT of work and duplicate code (that was in MyBaseClassTests already)
[TestFixture]
public class MyChildClassTests
{
[Test]
public void Expected_Returns_False_WhenPassed_1()
{
var expected = false;
var myChildClass = new Mock<MyChildClass> {CallBase = true};
myChildClass.Protected().Setup<bool>("MyMethod", 1).Returns(expected);
var result = myChildClass.Object.DoSomething(1);
Assert.AreEqual(expected, result);
}
[Test]
public void Expected_Returns_True_WhenPassed_1()
{
var expected = true;
var myChildClass = new Mock<MyChildClass> {CallBase = true};
myChildClass.Protected().Setup<bool>("MyMethod", 1).Returns(expected);
var result = myChildClass.Object.DoSomething(1);
Assert.AreEqual(expected, result);
}
}
Thanks everyone for your help! :)

Reflection only successful on first call in Blazor-State-Management

I discovered a weird behavior where I absolutely don't know where it comes from or how to fix it.
The issue arises with the blazor-state management (which is based on the mediator pattern) - library can be found here: https://timewarpengineering.github.io/blazor-state/.
Lets assume we have the following base class for an enumeration:
public abstract class Simple<TSimple> where TSimple: Simple<TSimple>
{
private readonly string _key;
protected Simple(string key)
{
_key = key;
}
public virtual string Key => _key;
public static TSimple Create(string key)
{
var obj = All.SingleOrDefault(e => e.Key == key);
return obj;
}
public static IReadOnlyCollection<TSimple> All => GetAll();
private static IReadOnlyCollection<TSimple> GetAll()
{
var enumerationType = typeof(TSimple);
return enumerationType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(info => enumerationType.IsAssignableFrom(info.FieldType))
.Select(info => info.GetValue(null))
.Cast<TSimple>()
.ToArray();
}
}
And the following enumeration implementation:
public class SimpleImpl : Simple<SimpleImpl>
{
public static readonly SimpleImpl One = new SimpleImpl("Important");
public static readonly SimpleImpl Two = new SimpleImpl("Urgent");
public static readonly SimpleImpl Three = new SimpleImpl("ImportantAndUrgent");
public static readonly SimpleImpl Four = new SimpleImpl("None");
private SimpleImpl(string key) : base(key)
{
}
}
So far so good.
I use this enumeration in a blazor app, where the data is retrieved via gRPC-Web from the backend, is transformed and added to the state.
So the code section of the Index.cshtml looks something like this:
#code
{
private AppState AppState => GetState<AppState>();
protected override async Task OnInitializedAsync()
{
foreach (var simple in new[] {"Important", "Urgent", "ImportantAndUrgent", "None"})
{
await Mediator.Send(new AppState.AddAction(simple));
}
}
This gets handled by the Handler:
public partial class AppState
{
public class AppHandler : ActionHandler<AddAction>
{
private AppState AppState => Store.GetState<AppState>();
public AppHandler(IStore store) : base(store)
{
}
public override async Task<Unit> Handle(AddAction aAction, CancellationToken aCancellationToken)
{
var simple = SimpleImpl.Create(aAction.Simple);
Console.WriteLine(simple == null); // First call false, afterwards true
AppState.Simples.Add(simple); // If I don't add the object to the state, Simple.Create always returns an object
return await Unit.Task;
}
}
}
And here is the problem. On the first try everything works, but if the functions gets called a second time (so my gRPC-Client returns multiple items) simple will always be null. If I remove the AppState.Simples.Add(simple) then it works again.
If I add the following code: Console.WriteLine(string.Join(",", SimpleImpl.All.Select(s => s.Key)); on the first run it prints all the possible values:
Important,Urgent,ImportantAndUrgent,None
On the second run, this:
,Urgent,,
Urgent was in the Dto in the first run. So it seems something to do with how the reference in the List is kept alive (which should not interfer with how the reflection part in Simple works).
Furthermore: in the GetAll() function of Simple everything works fine until the Select(info => .GetValue(null)) The FieldInfo-Property itself holds all 4 options. After GetValue and the cast there is only the last choosen one "alive".
The State-Entity looks like the following:
public partial class AppState : State<AppState>
{
public IList<SimpleImpl> Simples { get; private set; }
public override void Initialize()
{
Simples = new List<SimpleImpl>();
}
}
And the Action of this sample:
public partial class AppState
{
public class AddAction : IAction
{
public AddAction(string simple)
{
Simple = simple;
}
public string Simple { get; }
}
}
This code is running under .NET Core 3.1.
If anybody has a tip where the problem lays I would be very thankful.
Thanks to #steven-t-cramer how helped me on finding the issue.
Basically it all boils down to the Mediator.Send and State-Handling.
In the Blazor-State library a clone is created when one dispatches and handles an action (so you as a developer don't have to take care of that). But exactly this cloning messed up big time here because of the static nature of Simple(basically an enumeration class).
To get around that, the state can implement ICloneable and do this stuff on its own.
A very naive way to do would be that:
public partial class AppState : State<AppState>, ICloneable
{
private List<SimpleImpl> _simples = new List<SimpleImpl>();
public IReadOnlyList<SimpleImpl> Simples => _simples.AsReadOnly();
public override void Initialize()
{
_simples = new List<SimpleImpl>();
}
public object Clone()
{
var state = new AppState { _simples = _simples};
return state;
}
}

Entity Framework using context in static services MVC5

I have made an application that uses SignalR to occasionally fetch new data and show it to the users in real time. The problem is that my services are static (in my case I have named them Utilities) and inconsistently I receive errors which lead me to thinking that I have a concurrency problem with the context. Logically my services are best to be static. Here's my code, can you suggest me a better design pattern or something so I can still have my services static, but don't run into the errors from concurrent EF usage.
This is where I give each of my static services a DbContext to work with:
public static class Common
{
[ThreadStatic]
private static CryptoStatisticsDbContext _dbcontext;
internal static CryptoStatisticsDbContext DbContext => _dbcontext ?? (_dbcontext = new CryptoStatisticsDbContext());
}
Here are some of my services
TickerUtility
public static class TickerUtility
{
public delegate void UpdateTickerDelegate(int currencyId, decimal bid, decimal ask);
public static event UpdateTickerDelegate TickerUpdatedEvent;
public static List<Ticker> LastTickers { get; private set; } = new List<Ticker>();
public static IList<Ticker> GetAllTickers(Action<Ticker> actionToDoWithEachTicker)
{
var tickers = new ConcurrentBag<Ticker>();
var allCurrencies = Common.DbContext.Currencies.Include(c => c.Market).ToList();
Parallel.ForEach(allCurrencies, currency =>
//foreach (var currency in allCurrencies)
{
var ticker = GetTicker(currency);
tickers.Add(ticker);
actionToDoWithEachTicker?.Invoke(ticker);
});
return tickers.ToList();
}
}
MarketUtility
public static class MarketUtility
{
public static List<Market> Get()
{
return Common.DbContext.Markets.Include(m => m.Currencies).ToList();
}
}
SignalRUtility
public static class SignalRUtility
{
private static readonly IHubContext PublicMarketsHub = GlobalHost.ConnectionManager.GetHubContext<PublicMarketsHub>();
private static readonly IHubContext AdminMarketsHub = GlobalHost.ConnectionManager.GetHubContext<AdminMarketsHub>();
public static void SendNewTickersToClients(object state)
{
TickerUtility.GetAllTickers(ticker =>
{
if (ticker.IsVisibleForPublic)
PublicMarketsHub.Clients.Group(ticker.CurrencyId.ToString()).addNewTicker(ticker);
AdminMarketsHub.Clients.Group(ticker.CurrencyId.ToString()).addNewTicker(ticker);
});
}
public static void UpdateBalances(object state)
{
BalancesUtility.GetAvailableBalances(balance => AdminMarketsHub.Clients.All.showBalanceForMarket(balance),
(market) => AdminMarketsHub.Clients.All.showError($"Error getting {market} balances")
);
}
}
The BackgroundTimer which calls the static functions
public class BackgroundServerTimer : IRegisteredObject
{
private Timer ratesTimer;
private Timer balancesTimer;
private readonly TimeSpan ratesTimerInterval = new TimeSpan(0, 0, 0, 20);
private readonly TimeSpan balancesTimerInterval = new TimeSpan(0, 0, 0, 60);
public BackgroundServerTimer()
{
StartTimers();
}
private void StartTimers()
{
var delayStartby = new TimeSpan(0,0,0, 1);
ArbitrageUtility.AttachListenerToTickerChanges();
ratesTimer = new Timer(SignalRUtility.SendNewTickersToClients, null, delayStartby, ratesTimerInterval);
balancesTimer = new Timer(SignalRUtility.UpdateBalances, null, delayStartby, balancesTimerInterval);
}
public void Stop(bool immediate)
{
ratesTimer.Dispose();
balancesTimer.Dispose();
HostingEnvironment.UnregisterObject(this);
}
}
To elaborate on my problem see my HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
var markets = MarketUtility.Get().Select(m =>
{
m.Currencies = m.Currencies.OrderBy(c => c.Id).ToList();
return m;
});
var isUserAdmin = User.IsInRole("admin");
if (!isUserAdmin)
{
markets = markets.Select(m =>
{
m.Currencies = m.Currencies.Where(c => c.IsVisibleForPublic).ToList();
return m;
}).ToList();
markets = markets.Where(m => m.Currencies.Any()).ToList();
}
ViewBag.Markets = markets;
return isUserAdmin ? View("AdminIndex") : View();
}
}
One of my markets has 4 currencies. 2 public and 2 private. Sometimes when I view the app as a guest it shows me the 2 public, but after that I login with the admin but MarketUtility.Get() again returns me only the 2 public currencies (without me implying any .Where() clause). After some refreshes it gives me all 4 currencies. The same happens on edit and delete operations. I edit some entity (for example a currency) and the first couple of refreshes show different data. Sometimes the old data, sometimes the new data until (I suppose) EF clears it's cache and then I start to get the fresh data. I have disabled LazyLoading and ProxyCreation, now the problems occurs more rarely, but I know this is not the solution.
Parallel.ForEach(allCurrencies, currency =>
//foreach (var currency in allCurrencies)
{
var ticker = GetTicker(currency);
tickers.Add(ticker);
actionToDoWithEachTicker?.Invoke(ticker);
});
This is the line that throws exceptions like "Collection was Modified", "“The underlying provider failed on Open.” (this one I fixed using MARS, but again this is just a workaround). I don't get how can it throw collection was modified error when I use .ToList()
var allCurrencies = Common.DbContext.Currencies.Include(c => c.Market).ToList();
I want to make things the right way, to dispose the context when it's not needed, to consume less memory and everything, but still have my services static because it makes it easier for me (and I don't see a point in making them non static provided that all my methods are static

Automatically calling an init function whenever an object is used for the 1st time

I have an object that only initializes itself with barebones data when constructed (fast), and loads itself for real (slow) when first accessed. The idea is that I'm creating a lot of these barebones objects at startup and hash them into a map, then fully load each object whenever it is individually accessed for the first time. The problem is that I cannot guarantee how clients will interact with this object, there are multiple public methods that might be invoked.
Is there a good pattern to support this kind of situation? The obvious (and my current) solution is to track state with an internal bool, check against that bool in every function that might be invoked, and load that way. But that requires code duplication of that behavior across all public functions, and is vulnerable to errors.
I can imagine a single point-of-entry method that then dishes out behaviors based on a client request type etc., but before I go consider going down that road I want to see if there's a commonly accepted approach/pattern that I might not be aware of. I'm doing this in C#, but any insight is appreciated.
If I understood what you want to achieve, you are looking for the Proxy Design Pattern, more specifically, a virtual Proxy.
Refer to http://www.dofactory.com/net/proxy-design-pattern
A small example would be something like:
public abstract class IObjectProvider
{
public abstract IObjectProvider Object{get;}
public abstract void doStuff();
}
public class RealObject : IObjectProvider
{
public RealObject()
{
//Do very complicated and time taking stuff;
}
public override IObjectProvider Object
{
get { return this; }
}
public override void doStuff()
{
//do this stuff that these objects normally do
}
}
public class ObjectProxy : IObjectProvider
{
private IObjectProvider objectInstance = null;
public override IObjectProvider Object
{
get
{
if (objectInstance == null)
objectInstance = new RealObject();
return objectInstance;
}
}
public override void doStuff()
{
if(objectInstance!=null)
objectInstance.doStuff();
}
}
public class SkeletonClass
{
public IObjectProvider Proxy1 = new ObjectProxy();
public IObjectProvider Proxy2 = new ObjectProxy();
}
static void Main(String[] args)
{
//Objects Not Loaded
SkeletonClass skeleton = new SkeletonClass();
//Proxy1 loads object1 on demand
skeleton.Proxy1.Object.doStuff();
//Proxy2 not loaded object2 until someone needs it
}
Here's an example of dynamic proxy approach.
using System;
using System.Diagnostics;
using Castle.DynamicProxy; //Remember to include a reference, too. It's nugettable package is Castle.Core
namespace ConsoleApp
{
public class ActualClass
{
//Have static instances of two below for performance
private static ProxyGenerator pg = new ProxyGenerator();
private static ActualClassInterceptor interceptor = new ActualClassInterceptor();
//This is how we get ActualClass items that are wrapped in the Dynamic Proxy
public static ActualClass getActualClassInstance()
{
ActualClass instance = new ActualClass();
return pg.CreateClassProxyWithTarget<ActualClass>(instance, interceptor);
}
//Tracking whether init has been called
private bool initialized = false;
//Will be used as evidence of true initialization, i.e. no longer null
private int? someValue = null;
public void Initialize()
{
if (!initialized)
{
//do some initialization here.
someValue = -1; //Will only get set to non-null if we've run this line.
initialized = true;
}
}
//Any methods you want to intercept need to be virtual!
public virtual int replaceValue(int value)
{
//below will blow up, if someValue has not been set to -1 via Initialize();
int oldValue = someValue.Value;
someValue = value;
return oldValue;
}
//block off constructor from public to enforce use of getActualClassInstance
protected ActualClass() { }
}
public class ActualClassInterceptor : ActualClass, IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Call initialize before proceeding to call the intercepted method
//Worth noting that this is the only place we actually call Initialize()
((ActualClass)invocation.InvocationTarget).Initialize();
invocation.Proceed();
}
}
class Program
{
static void Main(string[] args)
{
ActualClass instance1 = ActualClass.getActualClassInstance();
ActualClass instance2 = ActualClass.getActualClassInstance();
int x1 = instance1.replaceValue(41);
int x2 = instance2.replaceValue(42);
int y1 = instance1.replaceValue(82);
Debug.Assert(y1 == 41);
int y2 = instance2.replaceValue(84);
Debug.Assert(y2 == 42);
var read = Console.ReadKey();
}
}
}

How do I run code before every test run in MSpec?

I'm trying to run some initialization code before a test. I've tried the suggestions in other questions, but it doesn't seem to work. My domain model raises events via the following class:
public static class DomainEvents
{
private static readonly object #lock = new object();
private static Action<IDomainEvent> raiseEvent;
public static void Raise<TEvent>(TEvent #event) where TEvent : class, IDomainEvent
{
// omitted for brevity
}
public static void RegisterEventPublisher(Action<IDomainEvent> eventPublisher)
{
lock (#lock)
{
raiseEvent = eventPublisher;
}
}
}
For testing purposes I would like to capture these events in a static list. What is the best way of doing this?
Update
The problem was caused by the order in which the tests are run (which as Alexander points out below, is not guaranteed). In one of my specs I had registered a mock event publisher. The fact that the spec would often run in different orders meant that a) to begin with I didn't know I had the issue (the "problem" spec always ran last) and b) Once I started having the issue, the number of failing tests would often vary between runs (making it even more confusing).
The lesson learned - clean up any static resources after each context has run. You can do this by implementing ICleanupAfterEveryContextInAssembly.
Maybe I'm misunderstanding the issue, but the basic pattern is:
public class WhenSomeDomainEventIsRaised
{
private IList<IDomainEvent> EventsRaised = new List<IDomainEvent>();
Establish context = () =>
{
// subscribe to events; when raised, add to EventsRaised list
}
}
If you want to do this for all tests or a subset of tests:
public abstract class DomainSpecification
{
protected IList<IDomainEvent> EventsRaised = new List<IDomainEvent>();
Establish context = () =>
{
// subscribe to events; when raised, add to EventsRaised list
}
}
You can have all specs that need this behaviour inherit from this class, and MSpec will take care of running all Establish blocks along the inheritance hierarchy.
This works for me:
using System;
using System.Collections.Generic;
using Machine.Specifications;
namespace AssemblyContextSpecs
{
public static class DomainEvents
{
static readonly object #lock = new object();
static Action<IDomainEvent> raiseEvent;
public static void Raise<TEvent>(TEvent #event) where TEvent : class, IDomainEvent
{
raiseEvent(#event);
}
public static void RegisterEventPublisher(Action<IDomainEvent> eventPublisher)
{
lock (#lock)
{
raiseEvent = eventPublisher;
}
}
}
public interface IDomainEvent
{
}
class FooEvent : IDomainEvent
{
}
public class DomainEventsContext : IAssemblyContext
{
internal static IList<IDomainEvent> Events = new List<IDomainEvent>();
public void OnAssemblyStart()
{
DomainEvents.RegisterEventPublisher(x => Events.Add(x));
}
public void OnAssemblyComplete()
{
}
}
public class When_a_domain_event_is_raised
{
Because of = () => DomainEvents.Raise(new FooEvent());
It should_capture_the_event =
() => DomainEventsContext.Events.ShouldContain(x => x.GetType() == typeof(FooEvent));
}
}
Shouldn't RegisterEventPublisher rather be RegisterEventSubscriber?

Categories