[PR] Implement tests for GradeCalculator and FinalGradeDeterminator, add documentation for aformentioned nodes #4

Merged
vincent merged 8 commits from 1-grade-generator/cijfer-determinator-calculator into 1-grade-generator/master 2025-10-07 10:07:12 +02:00
2 changed files with 45 additions and 43 deletions
Showing only changes of commit 2ab1c1c31f - Show all commits

View File

@@ -14,10 +14,17 @@ using namespace assignments::one::final_grade_determinator;
namespace assignments::one { namespace assignments::one {
class FakeDatabaseManager : public DatabaseManager { struct MockStoredResult {
vincent marked this conversation as resolved Outdated

These classes are called "Mock" classes, and thus I'd prefix them as "MockDatabaseManager" or something like that.

These classes are called "Mock" classes, and thus I'd prefix them as "MockDatabaseManager" or something like that.

Also interesting for your own information, GTest has a whole interface and setup around this; https://google.github.io/googletest/gmock_for_dummies.html

Also interesting for your own information, GTest has a whole interface and setup around this; https://google.github.io/googletest/gmock_for_dummies.html
StudentCourse sc;
int exam_count;
int final_grade;
};
class MockDatabaseManager : public DatabaseManager {
public: public:
explicit FakeDatabaseManager(rclcpp::Logger logger = rclcpp::get_logger("fake_db")) explicit MockDatabaseManager(rclcpp::Logger logger = rclcpp::get_logger("fake_db"))
: DatabaseManager(logger) {} : DatabaseManager(logger) {
}
bool is_connected() const override { bool is_connected() const override {
return true; // Always pretend we are connected return true; // Always pretend we are connected
@@ -29,15 +36,9 @@ public:
} }
void init_database() override { void init_database() override {
// No-op for fake } // no-op
}
struct StoredResult { std::vector<MockStoredResult> stored_results_;
StudentCourse sc;
int exam_count;
int final_grade;
};
std::vector<StoredResult> stored_results_;
}; };
} // namespace assignments::one } // namespace assignments::one
@@ -89,21 +90,25 @@ protected:
} }
void create_final_grade_determinator() { void create_final_grade_determinator() {
fake_db_ = std::make_unique<assignments::one::FakeDatabaseManager>(); fake_db_ = std::make_unique<assignments::one::MockDatabaseManager>();
final_grade_determinator_ = std::make_shared<FinalGradeDeterminator>(std::move(fake_db_)); final_grade_determinator_ = std::make_shared<FinalGradeDeterminator>(std::move(fake_db_));
} }
void spin_some_time(std::chrono::milliseconds duration = 100ms) { void spin_some_time(std::chrono::milliseconds duration = 100ms) {
auto start_time = std::chrono::steady_clock::now(); auto start_time = std::chrono::steady_clock::now();
while (std::chrono::steady_clock::now() - start_time < duration) { while (std::chrono::steady_clock::now() - start_time < duration) {
rclcpp::spin_some(test_node_); rclcpp::spin_some(test_node_);
if (final_grade_determinator_) { if (final_grade_determinator_) {
rclcpp::spin_some(final_grade_determinator_); rclcpp::spin_some(final_grade_determinator_);
} }
vincent marked this conversation as resolved Outdated

I personally prefer to split off with newlines in between the variables that are used together (or somewhat)

I personally prefer to split off with newlines in between the variables that are used together (or somewhat)
std::this_thread::sleep_for(10ms); std::this_thread::sleep_for(10ms);
} }
} }
std::unique_ptr<assignments::one::FakeDatabaseManager> fake_db_;
std::unique_ptr<assignments::one::MockDatabaseManager> fake_db_;
std::shared_ptr<rclcpp::Node> test_node_; std::shared_ptr<rclcpp::Node> test_node_;
std::shared_ptr<FinalGradeDeterminator> final_grade_determinator_; std::shared_ptr<FinalGradeDeterminator> final_grade_determinator_;
rclcpp::Subscription<g2_2025_interfaces::msg::Student>::SharedPtr student_subscriber_; rclcpp::Subscription<g2_2025_interfaces::msg::Student>::SharedPtr student_subscriber_;
@@ -113,6 +118,8 @@ protected:
std::vector<g2_2025_interfaces::srv::Exams::Request> service_requests_; std::vector<g2_2025_interfaces::srv::Exams::Request> service_requests_;
}; };
// ---- TEST CASES ----
TEST_F(FinalGradeDeterminatorTest, ConstructorTest) { TEST_F(FinalGradeDeterminatorTest, ConstructorTest) {
ASSERT_NO_THROW({ ASSERT_NO_THROW({
create_final_grade_determinator(); create_final_grade_determinator();

View File

@@ -77,27 +77,22 @@ protected:
// ---- TEST CASES ---- // ---- TEST CASES ----
TEST_F(GradeCalculatorTest, NormalAverage) TEST_F(GradeCalculatorTest, NormalAverage) {
{
EXPECT_EQ(call_service("Alice", { 80, 90, 70 }), 80); EXPECT_EQ(call_service("Alice", { 80, 90, 70 }), 80);
} }
TEST_F(GradeCalculatorTest, WesselBonus) TEST_F(GradeCalculatorTest, WesselBonus) {
{
EXPECT_EQ(call_service("Wessel", { 80, 90, 70 }), 90); EXPECT_EQ(call_service("Wessel", { 80, 90, 70 }), 90);
} }
TEST_F(GradeCalculatorTest, wesselBonus) TEST_F(GradeCalculatorTest, wesselBonus) {
{
EXPECT_EQ(call_service("wessel", { 80, 90, 70 }), 90); EXPECT_EQ(call_service("wessel", { 80, 90, 70 }), 90);
} }
TEST_F(GradeCalculatorTest, GradeTooHigh) TEST_F(GradeCalculatorTest, GradeTooHigh) {
{
EXPECT_EQ(call_service("Wessel", { 100, 100, 100 }), 100); EXPECT_EQ(call_service("Wessel", { 100, 100, 100 }), 100);
} }
TEST_F(GradeCalculatorTest, GradeTooLow) TEST_F(GradeCalculatorTest, GradeTooLow) {
{
EXPECT_EQ(call_service("Alice", { 0, 0, 0 }), 10); EXPECT_EQ(call_service("Alice", { 0, 0, 0 }), 10);
} }