Skip to content

Commit

Permalink
Projection tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mhelleborg committed Mar 8, 2024
1 parent da7db3e commit 8620fe1
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 49 deletions.
55 changes: 55 additions & 0 deletions Source/Testing/Projections/ProjectionAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Dolittle. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.Collections.Immutable;
using Dolittle.SDK.Projections;
using Dolittle.SDK.Testing.Aggregates.Events;

namespace Dolittle.SDK.Testing.Projections;

public class ProjectionAssertions<TProjection>
where TProjection : ReadModel, new()
{
readonly ImmutableDictionary<Key, TProjection> _projections;


public ProjectionAssertions(IDictionary<Key, TProjection> projections)
{
_projections = projections.ToImmutableDictionary();
}

public TProjection ReadModel(Key key)
{
return _projections.GetValueOrDefault(key) ?? throw new ReadModelDidNotExist(key);
}

public ReadModelValueAssertion<TProjection> HasReadModel(Key key)
{
return new ReadModelValueAssertion<TProjection>(ReadModel(key));
}

public void ReadModelDoesNotExist(Key key)
{
if (_projections.TryGetValue(key, out var projection))
{
throw new ReadModelExistedWhenItShouldNot(key, projection);
}
}
}

public class ReadModelExistedWhenItShouldNot : DolittleAssertionFailed
{
public ReadModelExistedWhenItShouldNot(Key key, object projection)
: base($"Read model for {key} existed when it should not. Projection: {projection}")
{
}
}

public class ReadModelDidNotExist : DolittleAssertionFailed
{
public ReadModelDidNotExist(Key key)
: base($"Read model for {key} did not exist")
{
}
}
29 changes: 1 addition & 28 deletions Source/Testing/Projections/ProjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,7 @@ protected void WithEvent(CommittedEvent committedEvent)
}
}

protected TProjection ReadModel(Key key)
{
return _projections.GetValueOrDefault(key) ?? throw new ReadModelDidNotExist(key);
}

protected void ReadModelShouldBeDeleted(Key key)
{
if (_projections.TryGetValue(key, out var projection))
{
throw new ReadModelExistedWhenItShouldNot(key, projection);
}
}
protected ProjectionAssertions<TProjection> AssertThat => new(_projections);

protected ProjectionTests(Action<IServiceCollection>? configureServices = default)
{
Expand Down Expand Up @@ -146,19 +135,3 @@ EventContext ToEventContext(CommittedEvent evt)
ExecutionContexts.Test);
}
}

public class ReadModelExistedWhenItShouldNot : Exception
{
public ReadModelExistedWhenItShouldNot(Key key, object projection)
: base($"Read model for {key} existed when it should not. Projection: {projection}")
{
}
}

public class ReadModelDidNotExist : Exception
{
public ReadModelDidNotExist(Key key)
: base($"Read model for {key} did not exist")
{
}
}
35 changes: 35 additions & 0 deletions Source/Testing/Projections/ReadModelValueAssertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Dolittle. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Dolittle.SDK.Testing.Aggregates.Events;

/// <summary>
/// Fluent interface element allowing assertions against a specific event.
/// </summary>
/// <typeparam name="T">The type of the event you wish to assert against.</typeparam>
/// <remarks>
/// Initializes a new instance of the <see cref="EventValueAssertion{T}"/> class with the event to assert against.
/// </remarks>
/// <param name="model">The event you wish to assert against.</param>
public class ReadModelValueAssertion<T>(T model)
where T : class
{
/// <summary>
/// Gets the event that is being asserted against.
/// </summary>
public T ReadModel { get; } = model;

/// <summary>
/// Asserts that the event passes the specified assertions.
/// </summary>
/// <param name="assertions">>A collection of assertions that you wish to perform.</param>
public void Where(params Action<T>[] assertions)
{
foreach (var assert in assertions)
{
assert(ReadModel);
}
}
}
11 changes: 6 additions & 5 deletions Tests/ProjectionsTests/AggregateProjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ public void ShouldUpdateProjectionOnAggregateChanges()
{
WhenAggregateMutated<TestAggregate>(_eventSourceId, agg => agg.Rename("Bob"));

var projection = ReadModel(_eventSourceId.Value);
projection.Name.Should().Be("Bob");
projection.TimesChanged.Should().Be(1);
AssertThat.HasReadModel(_eventSourceId.Value)
.Where(
it => it.Name.Should().Be("Bob"),
it => it.TimesChanged.Should().Be(1));
}

[Fact]
Expand All @@ -32,7 +33,7 @@ public void ShouldUpdateProjectionOnAggregateChangesAgain()
agg.Rename("Bobby");
});

var projection = ReadModel(_eventSourceId.Value);
var projection = AssertThat.ReadModel(_eventSourceId.Value);
projection.Name.Should().Be("Bobby");
projection.TimesChanged.Should().Be(2);
}
Expand All @@ -52,7 +53,7 @@ public void ShouldUpdateProjectionOnAggregateChangesAgainAndAgain()
agg.Rename("Bob");
});

var projection = ReadModel(_eventSourceId.Value);
var projection = AssertThat.ReadModel(_eventSourceId.Value);
projection.Name.Should().Be("Bob");
projection.TimesChanged.Should().Be(3);
}
Expand Down
6 changes: 3 additions & 3 deletions Tests/ProjectionsTests/ProjectionTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void CanMutateProjections()
SomeNumber = 10
}, when);

ReadModel(ProjectionKey).Should().BeEquivalentTo(new TestProjection
AssertThat.ReadModel(ProjectionKey).Should().BeEquivalentTo(new TestProjection
{
Id = ProjectionKey,
Content = "foo",
Expand All @@ -40,7 +40,7 @@ public void CanMutateProjectionsWithEventContextSignature()
SomeNumber = 42
});

ReadModel(ProjectionKey)!.TheNumber.Should().Be(42);
AssertThat.ReadModel(ProjectionKey)!.TheNumber.Should().Be(42);
}

[Fact]
Expand All @@ -52,6 +52,6 @@ public void CanDeleteProjections()
});
WithEvent(ProjectionKey, new DeleteEvent { Reason = "Just because" });

ReadModelShouldBeDeleted(ProjectionKey);
AssertThat.ReadModelDoesNotExist(ProjectionKey);
}
}
4 changes: 2 additions & 2 deletions Tests/ProjectionsTests/PropertyKeyedProjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void CanProjectOnProperty()
{
WithEvent(EventSource, new AnEvent(Property, "42"));

ReadModel(Property).TheValue.Should().Be("42");
AssertThat.ReadModel(Property).TheValue.Should().Be("42");
}

[Fact]
Expand All @@ -48,6 +48,6 @@ public void CanProjectDeleteOnProperty()
WithEvent(EventSource, new AnEvent(Property, "42"));
WithEvent(EventSource, new ADeleteEvent(Property));

ReadModelShouldBeDeleted(Property);
AssertThat.ReadModelDoesNotExist(Property);
}
}
8 changes: 4 additions & 4 deletions Tests/ProjectionsTests/ResultSignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ public void ShouldProjectOnResultProjectionContext()
{
WithEvent(EventSourceId, new ResultProjection(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnResultEventContext()
{
WithEvent(EventSourceId, new ResultEvent(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnResultEvent()
{
WithEvent(EventSourceId, new ResultEventContext(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
Expand All @@ -43,6 +43,6 @@ public void ShouldProjectOnResultDelete()
WithEvent(EventSourceId, new ResultEventContext(ExpectedContent));
WithEvent(EventSourceId, new ResultDelete());

ReadModelShouldBeDeleted(EventSourceId);
AssertThat.ReadModelDoesNotExist(EventSourceId);
}
}
8 changes: 4 additions & 4 deletions Tests/ProjectionsTests/ResultTypeSignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ public void ShouldProjectOnResultTypeProjectionContext()
{
WithEvent(EventSourceId, new ResultTypeProjection(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnResultTypeEventContext()
{
WithEvent(EventSourceId, new ResultTypeEvent(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnResultTypeEvent()
{
WithEvent(EventSourceId, new ResultTypeEventContext(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
Expand All @@ -43,6 +43,6 @@ public void ShouldProjectOnResultTypeDelete()
WithEvent(EventSourceId, new ResultTypeEventContext(ExpectedContent));
WithEvent(EventSourceId, new ResultTypeDelete());

ReadModelShouldBeDeleted(EventSourceId);
AssertThat.ReadModelDoesNotExist(EventSourceId);
}
}
6 changes: 3 additions & 3 deletions Tests/ProjectionsTests/VoidSignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ public void ShouldProjectOnVoidProjectionContext()
{
WithEvent(EventSourceId, new VoidProjection(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnVoidEventContext()
{
WithEvent(EventSourceId, new VoidEvent(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}

[Fact]
public void ShouldProjectOnVoidEvent()
{
WithEvent(EventSourceId, new VoidEventContext(ExpectedContent));

ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
AssertThat.ReadModel(EventSourceId)!.Content.Should().Be(ExpectedContent);
}
}

0 comments on commit 8620fe1

Please sign in to comment.