Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Test readability example
namespace WorldCupPredictions.UnitTests.Core.Calculators
{
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
using NUnit.Framework;
using WorldCupPredictions.Core;
using WorldCupPredictions.Core.Calculators;
using WorldCupPredictions.Core.Domain;
using WorldCupPredictions.Core.DTOs;
public class StandingsCalculatorTests
{
[Test]
public void Test_Calculate()
{
// Setup
var calculator = new StandingsCalculator(new PredictionResultCalculator(), new PointsCalculator());
var round1Id = Guid.NewGuid();
var round2Id = Guid.NewGuid();
var match1 = CreateMatch(matchId: Guid.NewGuid(), finalScore: null, roundId: round1Id);
var match2 = CreateMatch(matchId: Guid.NewGuid(), finalScore: new Score(2, 0), roundId: round1Id);
var match3 = CreateMatch(matchId: Guid.NewGuid(), finalScore: new Score(1, 1), roundId: round1Id);
var match4 = CreateMatch(matchId: Guid.NewGuid(), finalScore: new Score(2, 2), roundId: round2Id);
var match5 = CreateMatch(matchId: Guid.NewGuid(), finalScore: new Score(1, 3), roundId: round1Id);
var matches = new[] { match1, match2, match3, match4, match5 };
var player1 = CreatePlayer(predictionsByMatchId: new Dictionary<Guid, Prediction>());
var player2 = CreatePlayer(
predictionsByMatchId: new Dictionary<Guid, Prediction>
{
{ match1.Id, CreatePrediction(0, 0) },
{ match2.Id, CreatePrediction(2, 0) },
{ match3.Id, CreatePrediction(0, 0) },
{ match4.Id, CreatePrediction(2, 2) },
});
var player3 = CreatePlayer(
predictionsByMatchId: new Dictionary<Guid, Prediction>
{
{ match1.Id, CreatePrediction(0, 2) },
{ match2.Id, CreatePrediction(3, 1) },
{ match3.Id, CreatePrediction(0, 1) },
{ match5.Id, CreatePrediction(2, 1) }
});
var player4 = CreatePlayer(
predictionsByMatchId: new Dictionary<Guid, Prediction>
{
{ match4.Id, CreatePrediction(0, 0) }
});
var players = new[] { player1, player2, player3, player4 };
// Action
var roundStandings = calculator.Calculate(players, matches, roundId: round1Id);
// Check
var standings = roundStandings.Standings;
var expectedStandings = new[]
{
// Player 1 has no predictions at all; player 4 has no predictions for round 1
// Results for other rounds should not be included
CreateStanding(1, player2, CreatePredictionResults(1, 1, 0, 0), 2, 8),
CreateStanding(2, player3, CreatePredictionResults(0, 1, 1, 1), 3, 4),
};
Assert.That(standings.Count, Is.EqualTo(expectedStandings.Length));
foreach (var expectedTablePlacing in expectedStandings)
{
var actualTablePlacing =
standings.SingleOrDefault(tp => tp.Position == expectedTablePlacing.Position);
Assert.That(actualTablePlacing, Is.Not.Null);
Assert.That(actualTablePlacing.Player, Is.EqualTo(expectedTablePlacing.Player));
Assert.That(actualTablePlacing.CompletedMatchesPredicted, Is.EqualTo(expectedTablePlacing.CompletedMatchesPredicted));
Assert.That(actualTablePlacing.TotalPoints, Is.EqualTo(expectedTablePlacing.TotalPoints));
foreach (var predictionResult in expectedTablePlacing.PredictionResults.Keys)
{
Assert.That(actualTablePlacing.PredictionResults[predictionResult],
Is.EqualTo(expectedTablePlacing.PredictionResults[predictionResult]));
}
}
}
private static Match CreateMatch(Guid matchId, Score? finalScore, Guid roundId)
{
return new Match(matchId, null, null, Instant.MinValue, finalScore, roundId);
}
private static Prediction CreatePrediction(int homePrediction, int awayPrediction)
{
return new Prediction(Guid.NewGuid(), Guid.NewGuid(), new Score(homePrediction, awayPrediction));
}
private static Player CreatePlayer(IReadOnlyDictionary<Guid, Prediction> predictionsByMatchId)
{
return new Player(Guid.NewGuid(), null, predictionsByMatchId, null);
}
private static IReadOnlyDictionary<PredictionResult, int> CreatePredictionResults(
int exactScore,
int correctResult,
int oneTeamCorrect,
int wrong)
{
return new Dictionary<PredictionResult, int>
{
{ PredictionResult.ExactScore, exactScore },
{ PredictionResult.CorrectResult, correctResult },
{ PredictionResult.OneScoreCorrect, oneTeamCorrect },
{ PredictionResult.Wrong, wrong }
};
}
private static Standing CreateStanding(
int position,
Player player,
IReadOnlyDictionary<PredictionResult, int> predictionResults,
int matchesPredicted,
int totalPoints)
{
return new Standing(position, player, predictionResults, matchesPredicted, totalPoints);
}
}
}
namespace WorldCupPredictions.UnitTests.Core.Calculators
{
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using WorldCupPredictions.Core.Calculators;
using WorldCupPredictions.Core.Domain;
using static MatchCreator;
using static PlayerCreator;
using Match = WorldCupPredictions.Core.Domain.Match;
public class StandingsCalculatorTests
{
[Test]
public void When_there_are_no_players_standings_are_empty()
{
var calculator = CreateCalculator();
var matches = new[]
{
CompletedMatch(),
UpcomingMatch(),
};
var roundStandings = calculator.Calculate(
players: new List<Player>(),
matches: matches,
roundId: Guid.NewGuid());
Assert.That(roundStandings.Standings, Is.Empty);
Assert.That(roundStandings.Winners, Is.Empty);
}
[Test]
public void When_there_are_no_matches_standings_are_empty_and_round_is_not_completed()
{
var calculator = CreateCalculator();
var players = new[]
{
PlayerWithName("Player 1"),
PlayerWithName("Player 2"),
};
var roundStandings = calculator.Calculate(
players: players,
matches: new List<Match>(),
roundId: Guid.NewGuid());
Assert.That(roundStandings.Standings, Is.Empty);
Assert.That(roundStandings.Winners, Is.Empty);
Assert.That(roundStandings.RoundIsCompleted, Is.False);
}
[Test]
public void When_there_are_no_completed_matches_standings_exist_but_with_zero_points()
{
var calculator = CreateCalculator();
var roundId = Guid.NewGuid();
var match1 = UpcomingMatch(roundId);
var match2 = UpcomingMatch(roundId);
var player1 = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0)
.WithPrediction(match2, 1, 0)
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(match1, 2, 2)
.WithPrediction(match2, 1, 2)
.Build();
var players = new[] { player1, player2 };
var roundStandings = calculator.Calculate(
players: players,
matches: new[] { match1, match2 },
roundId: roundId);
Assert.That(roundStandings.Standings.Select(s => s.Player), Is.EquivalentTo(players));
Assert.That(roundStandings.Standings.Select(s => s.TotalPoints), Has.All.Zero);
Assert.That(roundStandings.Standings.Select(s => s.CompletedMatchesPredicted), Has.All.Zero);
}
[Test]
public void Standings_contain_number_of_completed_matches_predicted()
{
var calculator = CreateCalculator();
var roundId = Guid.NewGuid();
var completedMatch1 = CompletedMatch(roundId, 1, 0);
var completedMatch2 = CompletedMatch(roundId, 2, 2);
var upcomingMatch = UpcomingMatch(roundId);
var player1 = BuildPlayer("Player 1")
.WithPrediction(completedMatch1, 1, 0)
.WithPrediction(upcomingMatch, 1, 0)
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(completedMatch1, 2, 2)
.WithPrediction(completedMatch2, 1, 2)
.Build();
var roundStandings = calculator.Calculate(
players: new[] { player1, player2 },
matches: new[] { completedMatch1, completedMatch2, upcomingMatch },
roundId: roundId);
Assert.That(
roundStandings.Standings.Single(s => s.Player == player1).CompletedMatchesPredicted,
Is.EqualTo(1));
Assert.That(
roundStandings.Standings.Single(s => s.Player == player2).CompletedMatchesPredicted,
Is.EqualTo(2));
}
[Test]
public void Players_with_no_predictions_for_this_round_are_excluded_from_standings()
{
var calculator = CreateCalculator();
var roundId = Guid.NewGuid();
var matchForThisRound = UpcomingMatch(roundId);
var matchForDifferentRound = UpcomingMatch(Guid.NewGuid());
var player1 = BuildPlayer("Player 1")
.WithPrediction(matchForThisRound, 1, 0)
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(matchForDifferentRound, 2, 2)
.Build();
var roundStandings = calculator.Calculate(
players: new[] { player1, player2 },
matches: new[] { matchForThisRound, matchForDifferentRound },
roundId: roundId);
Assert.That(roundStandings.Standings.Count, Is.EqualTo(1));
Assert.That(roundStandings.Standings.Single().Player, Is.EqualTo(player1));
}
[Test]
public void Standings_contain_player_total_points_for_round()
{
var calculator = CreateCalculator(
predictionResultCalculator: new PredictionResultCalculator(),
pointsCalculator: new PointsCalculator());
var roundId = Guid.NewGuid();
var match1 = CompletedMatch(roundId, 1, 0);
var match2 = CompletedMatch(roundId, 2, 2);
var player1 = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 1, 0) // Wrong = 0
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(match1, 2, 2) // Wrong = 0
.WithPrediction(match2, 0, 3) // Wrong = 0
.Build();
var player3 = BuildPlayer("Player 3")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 2, 2) // Exact = 5
.Build();
var player4 = BuildPlayer("Player 4")
.WithPrediction(match1, 2, 1) // Correct result = 3
.WithPrediction(match2, 0, 0) // Correct result = 3
.Build();
var player5 = BuildPlayer("Player 5")
.WithPrediction(match1, 1, 1) // One correct = 1
.WithPrediction(match2, 1, 0) // Wrong = 0
.Build();
var roundStandings = calculator.Calculate(
players: new[] { player1, player2, player3, player4, player5 },
matches: new[] { match1, match2 },
roundId: roundId);
AssertPlayerTotalPoints(roundStandings.Standings, player1, expectedTotalPoints: 5);
AssertPlayerTotalPoints(roundStandings.Standings, player2, expectedTotalPoints: 0);
AssertPlayerTotalPoints(roundStandings.Standings, player3, expectedTotalPoints: 10);
AssertPlayerTotalPoints(roundStandings.Standings, player4, expectedTotalPoints: 6);
AssertPlayerTotalPoints(roundStandings.Standings, player5, expectedTotalPoints: 1);
}
[Test]
public void Standings_are_ordered_by_total_points_then_matches_predicted()
{
var calculator = CreateCalculator(
predictionResultCalculator: new PredictionResultCalculator(),
pointsCalculator: new PointsCalculator());
var roundId = Guid.NewGuid();
var match1 = CompletedMatch(roundId, 1, 0);
var match2 = CompletedMatch(roundId, 2, 2);
var player1 = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 1, 0) // Wrong = 0
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(match1, 2, 2) // Wrong = 0
.WithPrediction(match2, 0, 3) // Wrong = 0
.Build();
var player3 = BuildPlayer("Player 3")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 2, 2) // Exact = 5
.Build();
var player4 = BuildPlayer("Player 4")
.WithPrediction(match1, 2, 1) // Correct result = 3
.WithPrediction(match2, 0, 0) // Correct result = 3
.Build();
var player5 = BuildPlayer("Player 5")
.WithPrediction(match1, 1, 1) // One correct = 1
.WithPrediction(match2, 1, 0) // Wrong = 0
.Build();
var player6 = BuildPlayer("Player 6")
.WithPrediction(match1, 1, 1) // One correct = 1
.Build();
var players = new[] { player1, player2, player3, player4, player5, player6 };
var roundStandings = calculator.Calculate(
players: players,
matches: new[] { match1, match2 },
roundId: roundId);
var expectedOrder = new[]
{
player3, // 10pts
player4, // 6pts
player1, // 5pts
player6, // 1pts (1 predicted)
player5, // 1pts (2 predicted)
player2, // 0pts
};
Assert.That(roundStandings.Standings.Select(s => s.Player), Is.EqualTo(expectedOrder));
Assert.That(roundStandings.Standings.Select(s => s.Position), Is.EqualTo(Enumerable.Range(1, players.Length)));
}
[Test]
public void Standings_can_have_multiple_winners()
{
var calculator = CreateCalculator(
predictionResultCalculator: new PredictionResultCalculator(),
pointsCalculator: new PointsCalculator());
var roundId = Guid.NewGuid();
var match1 = CompletedMatch(roundId, 1, 0);
var match2 = CompletedMatch(roundId, 2, 2);
var match3 = CompletedMatch(roundId, 3, 0);
var player1 = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 1, 0) // Wrong = 0
.Build();
var player2 = BuildPlayer("Player 2")
.WithPrediction(match1, 2, 2) // Wrong = 0
.WithPrediction(match2, 2, 2) // Exact = 5
.Build();
var player3 = BuildPlayer("Player 3")
.WithPrediction(match1, 1, 0) // Exact = 5
.WithPrediction(match2, 0, 1) // Wrong = 0
.WithPrediction(match3, 0, 1) // Wrong = 0
.Build();
var players = new[] { player1, player2, player3 };
var roundStandings = calculator.Calculate(
players: players,
matches: new[] { match1, match2, match3 },
roundId: roundId);
// Player 3 is not included as they have predicted one extra match
Assert.That(roundStandings.Winners, Is.EquivalentTo(new[] { player1, player2 }));
}
[Test]
public void If_all_matches_have_a_final_score_entered_round_is_completed_and_winners_exist()
{
var calculator = CreateCalculator();
var roundId = Guid.NewGuid();
var match1 = CompletedMatch(roundId, 1, 0);
var match2 = CompletedMatch(roundId, 2, 2);
var matchForDifferentRound = UpcomingMatch(Guid.NewGuid());
var player = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0)
.Build();
var roundStandings = calculator.Calculate(
players: new[] { player },
matches: new[] { match1, match2, matchForDifferentRound },
roundId: roundId);
Assert.That(roundStandings.RoundIsCompleted, Is.True);
Assert.That(roundStandings.Winners, Is.Not.Empty);
}
[Test]
public void If_some_matches_do_not_have_a_final_score_entered_round_is_not_completed_and_there_are_no_winners()
{
var calculator = CreateCalculator();
var roundId = Guid.NewGuid();
var match1 = CompletedMatch(roundId, 1, 0);
var match2 = UpcomingMatch(roundId);
var matchForDifferentRound = UpcomingMatch(roundId);
var player = BuildPlayer("Player 1")
.WithPrediction(match1, 1, 0)
.Build();
var roundStandings = calculator.Calculate(
players: new[] { player },
matches: new[] { match1, match2, matchForDifferentRound },
roundId: roundId);
Assert.That(roundStandings.Winners, Is.Empty);
Assert.That(roundStandings.RoundIsCompleted, Is.False);
}
private static StandingsCalculator CreateCalculator(
IPredictionResultCalculator predictionResultCalculator = null,
IPointsCalculator pointsCalculator = null)
{
if (predictionResultCalculator == null)
{
predictionResultCalculator = Mock.Of<IPredictionResultCalculator>();
}
if (pointsCalculator == null)
{
pointsCalculator = Mock.Of<IPointsCalculator>();
}
return new StandingsCalculator(
predictionResultCalculator: predictionResultCalculator,
pointsCalculator: pointsCalculator);
}
private static void AssertPlayerTotalPoints(
IReadOnlyList<Standing> standings,
Player player,
int expectedTotalPoints)
{
var standing = standings.Single(s => s.Player == player);
Assert.That(standing.TotalPoints, Is.EqualTo(expectedTotalPoints));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment