Introduce unit testing on calculation objects
This commit is contained in:
@@ -1,19 +1,58 @@
|
||||
using Core.Calculation;
|
||||
using Tests.Parsers;
|
||||
using Core.Entities;
|
||||
using Tests.Builders;
|
||||
using Tests.Fixtures;
|
||||
|
||||
namespace Tests.Calculation;
|
||||
|
||||
[TestFixture]
|
||||
public class DataProcessingTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
BuilderExtensions.ResetAllBuilders();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEventStudentRankingsTest()
|
||||
{
|
||||
var events = TestEntityHandler.GetEvents();
|
||||
var students = TestEntityHandler.GetStudents(events);
|
||||
var rankings = TestEntityHandler.GetStudentEventRankings(students, events);
|
||||
// Create test data with explicit rankings
|
||||
var flight = EventDefinitionBuilder.Individual("Flight").Build();
|
||||
var coding = EventDefinitionBuilder.Individual("Coding").Build();
|
||||
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).Build();
|
||||
|
||||
foreach (var ranking in rankings)
|
||||
var alice = StudentBuilder.Default()
|
||||
.WithName("Alice", "Anderson")
|
||||
.WithGrade(9)
|
||||
.WithRanking(flight, rank: 1)
|
||||
.WithRanking(coding, rank: 2)
|
||||
.WithRanking(robotics, rank: 3)
|
||||
.Build();
|
||||
|
||||
var bob = StudentBuilder.Default()
|
||||
.WithName("Bob", "Brown")
|
||||
.WithGrade(10)
|
||||
.WithRanking(coding, rank: 1)
|
||||
.WithRanking(flight, rank: 3)
|
||||
.Build();
|
||||
|
||||
// Verify rankings are accessible
|
||||
Assert.That(alice.EventRankings, Has.Count.EqualTo(3));
|
||||
Assert.That(bob.EventRankings, Has.Count.EqualTo(2));
|
||||
|
||||
// Verify rankings are correctly associated
|
||||
var aliceFlightRanking = alice.EventRankings.First(r => r.EventDefinition == flight);
|
||||
Assert.That(aliceFlightRanking.Rank, Is.EqualTo(1));
|
||||
Assert.That(aliceFlightRanking.Student, Is.EqualTo(alice));
|
||||
|
||||
// Print rankings for verification (matching original test output)
|
||||
var allRankings = new[] { alice, bob }
|
||||
.SelectMany(s => s.EventRankings)
|
||||
.OrderBy(r => r.EventDefinition.Name)
|
||||
.ThenBy(r => r.Student.FirstName);
|
||||
|
||||
foreach (var ranking in allRankings)
|
||||
{
|
||||
Console.WriteLine(ranking.EventDefinition.Name);
|
||||
Console.WriteLine($"{ranking.Student.FirstName}: {ranking.Rank}");
|
||||
|
||||
@@ -1,24 +1,175 @@
|
||||
using Core.Calculation;
|
||||
using Core.Entities;
|
||||
using Core.Parsers;
|
||||
using Tests.Parsers;
|
||||
using Tests.Builders;
|
||||
using Tests.Fixtures;
|
||||
using EventAssignment = Core.Calculation.EventAssignment;
|
||||
|
||||
namespace Tests.Calculation;
|
||||
|
||||
[TestFixture]
|
||||
public class EventAssignmentTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
BuilderExtensions.ResetAllBuilders();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SolutionTest()
|
||||
public async Task SolutionTest()
|
||||
{
|
||||
var events = TestEntityHandler.GetEvents();
|
||||
var students = TestEntityHandler.GetStudents(events);
|
||||
// Create custom test data with sufficient rankings for EventAssignment
|
||||
// Need enough events and rankings to satisfy the default parameters:
|
||||
// - 2-4 events per student
|
||||
// - 6-8 effort points per student
|
||||
// - At least 1 regional event
|
||||
// - At least 1 on-site activity
|
||||
|
||||
var eventAssignment = new EventAssignment(events, students, new AssignmentParameters());
|
||||
var solution = eventAssignment.Solve().Result;
|
||||
var flight = EventDefinitionBuilder.Individual("Flight").AsRegionalEvent().Build();
|
||||
var coding = EventDefinitionBuilder.Individual("Coding").AsRegionalEvent().Build();
|
||||
var speech = EventDefinitionBuilder.Individual("Prepared Speech").AsOnSite().Build();
|
||||
var photo = EventDefinitionBuilder.Individual("Digital Photography").Build();
|
||||
var essays = EventDefinitionBuilder.Individual("Essays on Technology").Build();
|
||||
|
||||
//var teamWriter = new TeamWriter(solution.Teams, @"c:\temp\teams.csv");
|
||||
//teamWriter.Write();
|
||||
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().AsOnSite().Build();
|
||||
var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build();
|
||||
var webDesign = EventDefinitionBuilder.Team("Website Design", 3, 6).Build();
|
||||
var videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).Build();
|
||||
var engineering = EventDefinitionBuilder.Team("Engineering Design", 3, 6).AsOnSite().Build();
|
||||
|
||||
var events = new[] { flight, coding, speech, photo, essays, robotics, biotech, webDesign, videoGame, engineering };
|
||||
|
||||
// Create students with diverse rankings (each ranks 7-8 events)
|
||||
var alice = StudentBuilder.Default()
|
||||
.WithName("Alice", "A").WithGrade(9)
|
||||
.WithRanking(flight, 1).WithRanking(robotics, 2).WithRanking(biotech, 3)
|
||||
.WithRanking(speech, 4).WithRanking(webDesign, 5).WithRanking(coding, 6)
|
||||
.WithRanking(videoGame, 7)
|
||||
.Build();
|
||||
|
||||
var bob = StudentBuilder.Default()
|
||||
.WithName("Bob", "B").WithGrade(10)
|
||||
.WithRanking(coding, 1).WithRanking(engineering, 2).WithRanking(robotics, 3)
|
||||
.WithRanking(speech, 4).WithRanking(biotech, 5).WithRanking(photo, 6)
|
||||
.WithRanking(videoGame, 7)
|
||||
.Build();
|
||||
|
||||
var carol = StudentBuilder.Default()
|
||||
.WithName("Carol", "C").WithGrade(11)
|
||||
.WithRanking(photo, 1).WithRanking(webDesign, 2).WithRanking(engineering, 3)
|
||||
.WithRanking(speech, 4).WithRanking(biotech, 5).WithRanking(flight, 6)
|
||||
.WithRanking(coding, 7)
|
||||
.Build();
|
||||
|
||||
var david = StudentBuilder.Default()
|
||||
.WithName("David", "D").WithGrade(9)
|
||||
.WithRanking(essays, 1).WithRanking(robotics, 2).WithRanking(videoGame, 3)
|
||||
.WithRanking(engineering, 4).WithRanking(speech, 5).WithRanking(coding, 6)
|
||||
.WithRanking(biotech, 7)
|
||||
.Build();
|
||||
|
||||
var eve = StudentBuilder.Default()
|
||||
.WithName("Eve", "E").WithGrade(10)
|
||||
.WithRanking(flight, 1).WithRanking(webDesign, 2).WithRanking(engineering, 3)
|
||||
.WithRanking(robotics, 4).WithRanking(photo, 5).WithRanking(coding, 6)
|
||||
.WithRanking(speech, 7)
|
||||
.Build();
|
||||
|
||||
var frank = StudentBuilder.Default()
|
||||
.WithName("Frank", "F").WithGrade(11)
|
||||
.WithRanking(coding, 1).WithRanking(biotech, 2).WithRanking(videoGame, 3)
|
||||
.WithRanking(speech, 4).WithRanking(webDesign, 5).WithRanking(flight, 6)
|
||||
.WithRanking(robotics, 7)
|
||||
.Build();
|
||||
|
||||
var students = new[] { alice, bob, carol, david, eve, frank };
|
||||
|
||||
// Use relaxed parameters for test
|
||||
var parameters = new AssignmentParameters(
|
||||
effortLowerBound: 4,
|
||||
effortUpperBound: 7,
|
||||
eventsLowerBound: 2,
|
||||
eventsUpperBound: 4,
|
||||
requireRegional: false, // Relax for test simplicity
|
||||
requireOnSite: false // Relax for test simplicity
|
||||
);
|
||||
|
||||
var eventAssignment = new EventAssignment(events, students, parameters);
|
||||
var solution = await eventAssignment.Solve();
|
||||
|
||||
// Verify solution
|
||||
Assert.That(solution.Teams, Is.Not.Null);
|
||||
Assert.That(solution.Status, Is.EqualTo("Optimal").Or.EqualTo("Feasible"),
|
||||
$"Solution should be Optimal or Feasible, but was {solution.Status}");
|
||||
|
||||
// Print solution summary for verification
|
||||
Console.WriteLine($"Solution Status: {solution.Status}");
|
||||
Console.WriteLine($"Teams Created: {solution.Teams.Length}");
|
||||
Console.WriteLine($"Students Assigned: {solution.Teams.SelectMany(t => t.Students).Distinct().Count()}");
|
||||
|
||||
// Verify each team has valid structure
|
||||
foreach (var team in solution.Teams)
|
||||
{
|
||||
Assert.That(team.Event, Is.Not.Null, $"Team should have an event");
|
||||
Assert.That(team.Students, Is.Not.Empty, $"Team for {team.Event.Name} should have students");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task SolutionTest_WithMinimalData()
|
||||
{
|
||||
// Test with minimal custom data to verify basic functionality
|
||||
var flight = EventDefinitionBuilder.Individual("Flight").Build();
|
||||
var coding = EventDefinitionBuilder.Individual("Coding").Build();
|
||||
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().Build();
|
||||
var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build();
|
||||
|
||||
var events = new[] { flight, coding, robotics, biotech };
|
||||
|
||||
var alice = StudentBuilder.Default()
|
||||
.WithName("Alice", "A")
|
||||
.WithGrade(9)
|
||||
.WithRanking(flight, 1)
|
||||
.WithRanking(robotics, 2)
|
||||
.WithRanking(biotech, 3)
|
||||
.Build();
|
||||
|
||||
var bob = StudentBuilder.Default()
|
||||
.WithName("Bob", "B")
|
||||
.WithGrade(10)
|
||||
.WithRanking(coding, 1)
|
||||
.WithRanking(robotics, 2)
|
||||
.WithRanking(biotech, 3)
|
||||
.Build();
|
||||
|
||||
var carol = StudentBuilder.Default()
|
||||
.WithName("Carol", "C")
|
||||
.WithGrade(11)
|
||||
.WithRanking(flight, 2)
|
||||
.WithRanking(biotech, 1)
|
||||
.WithRanking(robotics, 3)
|
||||
.Build();
|
||||
|
||||
var students = new[] { alice, bob, carol };
|
||||
|
||||
// Run the event assignment algorithm with minimal data
|
||||
var parameters = new AssignmentParameters(
|
||||
effortLowerBound: 2,
|
||||
effortUpperBound: 4,
|
||||
eventsLowerBound: 2,
|
||||
eventsUpperBound: 3,
|
||||
requireRegional: false,
|
||||
requireOnSite: false
|
||||
);
|
||||
|
||||
var eventAssignment = new EventAssignment(events, students, parameters);
|
||||
var solution = await eventAssignment.Solve();
|
||||
|
||||
// Verify solution
|
||||
Assert.That(solution.Status, Is.EqualTo("Optimal").Or.EqualTo("Feasible"));
|
||||
Assert.That(solution.Teams, Is.Not.Empty, "Should create some teams");
|
||||
|
||||
Console.WriteLine($"Minimal Test - Status: {solution.Status}");
|
||||
Console.WriteLine($"Teams: {solution.Teams.Length}");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
using Core.Calculation;
|
||||
using Core.Entities;
|
||||
using Tests.Parsers;
|
||||
using Tests.Builders;
|
||||
using Tests.Fixtures;
|
||||
|
||||
namespace Tests.Calculation;
|
||||
|
||||
[TestFixture]
|
||||
public class TeamSchedulerTest
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
BuilderExtensions.ResetAllBuilders();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Prototype_Test()
|
||||
{
|
||||
@@ -17,40 +24,57 @@ public class TeamSchedulerTest
|
||||
[Test]
|
||||
public void SolutionTest()
|
||||
{
|
||||
var events = TestEntityHandler.GetEvents();
|
||||
var students = TestEntityHandler.GetStudents(events);
|
||||
|
||||
var allTeams = TestEntityHandler.GetTeams(events, students);
|
||||
var teams = allTeams;
|
||||
// Create test data with regional team events for TeamScheduler
|
||||
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().Build();
|
||||
var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build();
|
||||
var webDesign = EventDefinitionBuilder.Team("Website Design", 3, 6).AsRegionalEvent().Build();
|
||||
var videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).AsRegionalEvent().Build();
|
||||
var engineering = EventDefinitionBuilder.Team("Engineering Design", 3, 6).AsRegionalEvent().Build();
|
||||
var cybersecurity = EventDefinitionBuilder.Team("Cybersecurity", 2, 6).AsRegionalEvent().Build();
|
||||
|
||||
teams =
|
||||
(from e in events
|
||||
from t in teams
|
||||
where t.Event == e
|
||||
//&& t.Students.Count > 1
|
||||
&& (e.EventFormat == EventFormat.Team && e.RegionalEvent)
|
||||
select t).ToArray();
|
||||
teams =
|
||||
teams.Where(t => !t.Event.Name.Contains("Tech Bowl")).ToArray();
|
||||
var events = new[] { robotics, biotech, webDesign, videoGame, engineering, cybersecurity };
|
||||
|
||||
//var eventAssignment = new EventAssignment(events, students);
|
||||
//var teams = eventAssignment.Solve();
|
||||
// Create students
|
||||
var alice = StudentBuilder.Default().WithName("Alice", "A").WithGrade(9).WithTsaYear(1).Build();
|
||||
var bob = StudentBuilder.Default().WithName("Bob", "B").WithGrade(10).WithTsaYear(2).Build();
|
||||
var carol = StudentBuilder.Default().WithName("Carol", "C").WithGrade(11).WithTsaYear(3).Build();
|
||||
var david = StudentBuilder.Default().WithName("David", "D").WithGrade(9).WithTsaYear(1).Build();
|
||||
var eve = StudentBuilder.Default().WithName("Eve", "E").WithGrade(10).WithTsaYear(2).Build();
|
||||
var frank = StudentBuilder.Default().WithName("Frank", "F").WithGrade(11).WithTsaYear(3).Build();
|
||||
var grace = StudentBuilder.Default().WithName("Grace", "G").WithGrade(9).WithTsaYear(1).Build();
|
||||
var henry = StudentBuilder.Default().WithName("Henry", "H").WithGrade(10).WithTsaYear(2).Build();
|
||||
|
||||
TeamSchedulerSolution solution;
|
||||
if (true)
|
||||
var students = new[] { alice, bob, carol, david, eve, frank, grace, henry };
|
||||
|
||||
// Create teams with student assignments
|
||||
var allTeams = new[]
|
||||
{
|
||||
var teamScheduler = new TeamScheduler(teams, 3, students);
|
||||
solution = teamScheduler.Solve();
|
||||
}
|
||||
else
|
||||
{
|
||||
var teamScheduler = new TeamScheduler_DecisionTree(teams, 3);
|
||||
solution = teamScheduler.Solve();
|
||||
}
|
||||
TeamBuilder.Default().ForEvent(robotics).WithStudentsAndCaptain(alice, bob, carol).WithIdentifier("Robotics A").Build(),
|
||||
TeamBuilder.Default().ForEvent(biotech).WithStudentsAndCaptain(david, eve, frank).WithIdentifier("Biotech A").Build(),
|
||||
TeamBuilder.Default().ForEvent(webDesign).WithStudentsAndCaptain(grace, henry, alice).WithIdentifier("WebDesign A").Build(),
|
||||
TeamBuilder.Default().ForEvent(videoGame).WithStudentsAndCaptain(bob, david).WithIdentifier("VideoGame A").Build(),
|
||||
TeamBuilder.Default().ForEvent(engineering).WithStudentsAndCaptain(carol, eve, frank).WithIdentifier("Engineering A").Build(),
|
||||
TeamBuilder.Default().ForEvent(cybersecurity).WithStudentsAndCaptain(grace, henry).WithIdentifier("Cybersecurity A").Build()
|
||||
};
|
||||
|
||||
//solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup);
|
||||
//solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents);
|
||||
// Filter to only regional team events (matching original test logic)
|
||||
var teams = allTeams
|
||||
.Where(t => t.Event.EventFormat == EventFormat.Team && t.Event.RegionalEvent)
|
||||
.ToArray();
|
||||
|
||||
// Verify we have teams to schedule
|
||||
Assert.That(teams, Is.Not.Empty, "Should have teams to schedule");
|
||||
|
||||
// Run TeamScheduler with 3 time slots
|
||||
var teamScheduler = new TeamScheduler(teams, 3, students);
|
||||
var solution = teamScheduler.Solve();
|
||||
|
||||
// Verify solution
|
||||
Assert.That(solution, Is.Not.Null);
|
||||
Assert.That(solution.TimeSlots, Is.Not.Null);
|
||||
Assert.That(solution.TimeSlots.Length, Is.EqualTo(3), "Should have 3 time slots");
|
||||
|
||||
// Print solution (matching original test output format)
|
||||
var i = 1;
|
||||
foreach (var slot in solution.TimeSlots)
|
||||
{
|
||||
@@ -73,17 +97,10 @@ public class TeamSchedulerTest
|
||||
}
|
||||
|
||||
var unassigned = UnassignedStudentScheduler.UnassignedStudents(students, slot.Teams).ToList();
|
||||
|
||||
|
||||
if (unassigned.Any())
|
||||
Console.WriteLine("\tunassigned");
|
||||
Console.WriteLine($"\t\t{string.Join(", ", unassigned.Select(s => s.FirstName))}");
|
||||
}
|
||||
|
||||
//var allScheduledTeams = timeSlots.SelectMany(list => list).GroupBy(t => t.Name).SelectMany(g => g).Distinct();
|
||||
//foreach (var allScheduledTeam in allScheduledTeams.OrderBy(a => a.Name))
|
||||
//{
|
||||
// Console.WriteLine($"{allScheduledTeam.Name}");
|
||||
// Console.WriteLine($"\t{string.Join(", ", allScheduledTeam.Students.Select(s => s.FirstName))}");
|
||||
//}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user