Skip to content

Commit

Permalink
Add some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pomianowski committed May 12, 2024
1 parent 149248d commit 029d2fa
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 12 deletions.
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 🚎 ReflectionEventing

[Created with ❤ in Poland by lepo.co](https://dev.lepo.co/)
Unleash the power of decoupled design with eventing. ReflectionEventing empowers developers to create simple events between services using DI in WPF, WinForms, or CLI applications. By facilitating better Inversion of Control, ReflectionEventing helps reduce coupling, enhancing the modularity and flexibility of your applications.
ReflectionEventing is a powerful tool for developers looking to create decoupled designs in WPF, WinForms, or CLI applications. By leveraging the power of Dependency Injection (DI) and eventing, ReflectionEventing promotes better Inversion of Control (IoC), reducing coupling and enhancing the modularity and flexibility of your applications.

[![GitHub license](https://img.shields.io/github/license/lepoco/reflectioneventing)](https://github.com/lepoco/reflectioneventing/blob/master/LICENSE) [![Nuget](https://img.shields.io/nuget/v/ReflectionEventing)](https://www.nuget.org/packages/ReflectionEventing/) [![Nuget](https://img.shields.io/nuget/dt/ReflectionEventing?label=nuget)](https://www.nuget.org/packages/ReflectionEventing/) [![Sponsors](https://img.shields.io/github/sponsors/lepoco)](https://github.com/sponsors/lepoco)

## 👀 What does this repo contain?

The repository contains NuGet package source code, which uses C# reflection to register services that can be used to listen for local events.
This repository houses the source code for the ReflectionEventing NuGet package. The package utilizes C# reflection to register services that can listen for and respond to local events.

## Gettings started

Expand All @@ -28,25 +28,29 @@ dotnet add package ReflectionEventing.DependencyInjection
NuGet\Install-Package ReflectionEventing.DependencyInjection
```

### Usage
### 🛠️ How to Use ReflectionEventing

#### Register consumers and bus
#### 1. Register Consumers and the Event Bus

In this step, we register our ViewModel as a singleton and add it as a consumer to the event bus. This allows the ViewModel to listen for events published on the bus.

```csharp
IHost host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
_ = services.AddSingleton<MainWindowViewModel>();
_ = services.AddEventBus(e =>
services.AddSingleton<MainWindowViewModel>();
services.AddEventBus(e =>
{
_ = e.AddConsumer<MainWindowViewModel>();
e.AddConsumer<MainWindowViewModel>();
});
}
)
.Build();
```

#### Publish your event
#### 2. Publish Events

Here, we create a background service that publishes an event on the event bus. This event could be anything - in this case, we're publishing a `BackgroundTicked` event.

```csharp
public class MyBackgroundService(IEventBus eventBus)
Expand All @@ -58,7 +62,9 @@ public class MyBackgroundService(IEventBus eventBus)
}
```

#### Now you can listen for the event
#### 3. Listen for Events

Finally, we implement the `IConsumer<T>` interface in our ViewModel. This allows the ViewModel to consume `BackgroundTicked` events. When a `BackgroundTicked` event is published, the `ConsumeAsync` method is called, and we update the `CurrentTick` property.

```csharp
public partial class MainWindowViewModel : ObservableObject, IConsumer<BackgroundTicked>
Expand All @@ -77,7 +83,7 @@ public partial class MainWindowViewModel : ObservableObject, IConsumer<Backgroun

## Compilation

Use Visual Studio 2022 and invoke the .sln.
To build the project, use Visual Studio 2022 and open the .sln file.

Visual Studio
**ReflectionEventing** is an Open Source project. You are entitled to download and use the freely available Visual Studio Community Edition to build, run or develop for ReflectionEventing. As per the Visual Studio Community Edition license, this applies regardless of whether you are an individual or a corporate user.
Expand Down
15 changes: 13 additions & 2 deletions ReflectionEventing.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEventing.Autofac", "src\ReflectionEventing.Autofac\ReflectionEventing.Autofac.csproj", "{6023E50F-2B4D-4315-B85D-9E8A12746045}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReflectionEventing.Autofac", "src\ReflectionEventing.Autofac\ReflectionEventing.Autofac.csproj", "{6023E50F-2B4D-4315-B85D-9E8A12746045}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEventing.DependencyInjection", "src\ReflectionEventing.DependencyInjection\ReflectionEventing.DependencyInjection.csproj", "{09F0D6A2-3791-4173-A612-98E6EA92FCC4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReflectionEventing.DependencyInjection", "src\ReflectionEventing.DependencyInjection\ReflectionEventing.DependencyInjection.csproj", "{09F0D6A2-3791-4173-A612-98E6EA92FCC4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7A58AE12-65AA-4E1B-B5DB-CBD2732D1AE7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEventing.UnitTests", "tests\ReflectionEventing.UnitTests\ReflectionEventing.UnitTests.csproj", "{7F506A5A-1F70-49CB-B371-428DFA573451}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -43,10 +47,17 @@ Global
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Release|Any CPU.Build.0 = Release|Any CPU
{7F506A5A-1F70-49CB-B371-428DFA573451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F506A5A-1F70-49CB-B371-428DFA573451}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F506A5A-1F70-49CB-B371-428DFA573451}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F506A5A-1F70-49CB-B371-428DFA573451}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7F506A5A-1F70-49CB-B371-428DFA573451} = {7A58AE12-65AA-4E1B-B5DB-CBD2732D1AE7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B017BA78-67A5-4D0F-92A3-671B0D8A2911}
EndGlobalSection
Expand Down
45 changes: 45 additions & 0 deletions tests/ReflectionEventing.UnitTests/EventBusBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

using FluentAssertions;

namespace ReflectionEventing.UnitTests;

public sealed class EventBusBuilderTests
{
private readonly EventBusBuilder _eventBusBuilder = new EventBusBuilder();

[Fact]
public void AddConsumer_ShouldAddConsumerToDictionary()
{
Type consumerType = typeof(MySampleConsumer);

_eventBusBuilder.AddConsumer(consumerType);

IDictionary<Type, IEnumerable<Type>> consumers = _eventBusBuilder.GetConsumers();
_ = consumers.Should().ContainKey(consumerType);
}

[Fact]
public void AddConsumer_ShouldAddEventTypeToConsumerInDictionary()
{
Type consumerType = typeof(MySampleConsumer);

_eventBusBuilder.AddConsumer(consumerType);

IDictionary<Type, IEnumerable<Type>> consumers = _eventBusBuilder.GetConsumers();
_ = consumers[consumerType].Should().Contain(typeof(TestEvent));
}

public sealed record TestEvent;

public sealed record MySampleConsumer : IConsumer<TestEvent>
{
public Task ConsumeAsync(TestEvent payload, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}
52 changes: 52 additions & 0 deletions tests/ReflectionEventing.UnitTests/EventBusTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

namespace ReflectionEventing.UnitTests;

public sealed class EventBusTests
{
private readonly IConsumerProvider _consumerProvider;
private readonly IConsumerTypesProvider _consumerTypesProvider;
private readonly EventBus _eventBus;

public EventBusTests()
{
_consumerProvider = Substitute.For<IConsumerProvider>();
_consumerTypesProvider = Substitute.For<IConsumerTypesProvider>();
_eventBus = new EventBus(_consumerProvider, _consumerTypesProvider);
}

[Fact]
public async Task PublishAsync_ShouldCallConsumeAsyncOnAllConsumers()
{
TestEvent testEvent = new();
Type consumerType = typeof(IConsumer<TestEvent>);
IConsumer<TestEvent> consumer = Substitute.For<IConsumer<TestEvent>>();

_ = _consumerTypesProvider.GetConsumerTypes<TestEvent>().Returns([consumerType]);
_ = _consumerProvider.GetConsumerTypes(consumerType).Returns([consumer]);

await _eventBus.PublishAsync(testEvent, CancellationToken.None);

await consumer.Received().ConsumeAsync(testEvent, Arg.Any<CancellationToken>());
}

[Fact]
public async Task Publish_ShouldCallPublishAsync()
{
TestEvent testEvent = new();
Type consumerType = typeof(IConsumer<TestEvent>);
IConsumer<TestEvent> consumer = Substitute.For<IConsumer<TestEvent>>();

_ = _consumerTypesProvider.GetConsumerTypes<TestEvent>().Returns([consumerType]);
_ = _consumerProvider.GetConsumerTypes(consumerType).Returns([consumer]);

_eventBus.Publish(testEvent);

await consumer.Received().ConsumeAsync(testEvent, Arg.Any<CancellationToken>());
}

public sealed record TestEvent;
}
11 changes: 11 additions & 0 deletions tests/ReflectionEventing.UnitTests/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

global using NSubstitute;
global using System;
global using System.Collections.Generic;
global using System.Threading;
global using System.Threading.Tasks;
global using Xunit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions"/>
<PackageReference Include="NSubstitute"/>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ReflectionEventing\ReflectionEventing.csproj" />
</ItemGroup>

</Project>

0 comments on commit 029d2fa

Please sign in to comment.