generated from wessel/boilerplate
[PR] Implement tests for GradeCalculator and FinalGradeDeterminator, add documentation for aformentioned nodes #4
@@ -141,6 +141,25 @@ if(BUILD_TESTING)
|
|||||||
rclcpp
|
rclcpp
|
||||||
g2_2025_interfaces
|
g2_2025_interfaces
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add gtest for FinalGradeDeterminator
|
||||||
|
ament_add_gtest(${PROJECT_NAME}_test_final_grade_determinator
|
||||||
|
test/FinalGradeDeterminator.test.cpp
|
||||||
|
src/final_grade_determinator/nodes/FinalGradeDeterminator.cpp
|
||||||
|
src/database/DatabaseManager.cpp
|
||||||
|
src/config/ConfigManager.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(${PROJECT_NAME}_test_final_grade_determinator PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/final_grade_determinator
|
||||||
|
)
|
||||||
|
ament_target_dependencies(${PROJECT_NAME}_test_final_grade_determinator
|
||||||
|
rclcpp
|
||||||
|
g2_2025_interfaces
|
||||||
|
)
|
||||||
|
target_link_libraries(${PROJECT_NAME}_test_final_grade_determinator
|
||||||
|
pqxx pq tomlplusplus::tomlplusplus
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
ament_package()
|
ament_package()
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <rclcpp/rclcpp.hpp>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "final_grade_determinator/nodes/FinalGradeDeterminator.hpp"
|
||||||
|
#include "database/DatabaseManager.hpp"
|
||||||
|
#include "g2_2025_interfaces/msg/exam.hpp"
|
||||||
|
#include "g2_2025_interfaces/msg/student.hpp"
|
||||||
|
#include "g2_2025_interfaces/srv/exams.hpp"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
using namespace assignments::one::final_grade_determinator;
|
||||||
|
|
||||||
|
class FinalGradeDeterminatorTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
rclcpp::init(0, nullptr);
|
||||||
|
|
||||||
|
test_node_ = std::make_shared<rclcpp::Node>("test_node");
|
||||||
|
|
||||||
|
// Subscriber to capture student messages
|
||||||
|
student_subscriber_ = test_node_->create_subscription<g2_2025_interfaces::msg::Student>(
|
||||||
|
"student_course_management", 10,
|
||||||
|
[this](const g2_2025_interfaces::msg::Student::SharedPtr msg) {
|
||||||
|
received_student_messages_.push_back(*msg);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Publisher to send exam messages
|
||||||
|
exam_publisher_ = test_node_->create_publisher<g2_2025_interfaces::msg::Exam>(
|
||||||
|
"exam_results", 10
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock service server for grade calculator
|
||||||
|
grade_calculator_service_ = test_node_->create_service<g2_2025_interfaces::srv::Exams>(
|
||||||
|
"grade_calculator_service",
|
||||||
|
[this](const g2_2025_interfaces::srv::Exams::Request::SharedPtr request,
|
||||||
|
g2_2025_interfaces::srv::Exams::Response::SharedPtr response) {
|
||||||
|
service_requests_.push_back(*request);
|
||||||
|
// Mock calculation - average of grades
|
||||||
|
int sum = 0;
|
||||||
|
for (const auto& grade : request->exam_grades) {
|
||||||
|
sum += grade;
|
||||||
|
}
|
||||||
|
response->result = sum / request->exam_grades.size();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
received_student_messages_.clear();
|
||||||
|
service_requests_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
final_grade_determinator_.reset();
|
||||||
|
test_node_.reset();
|
||||||
|
rclcpp::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_final_grade_determinator() {
|
||||||
|
final_grade_determinator_ = std::make_shared<FinalGradeDeterminator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void spin_some_time(std::chrono::milliseconds duration = 100ms) {
|
||||||
|
auto start_time = std::chrono::steady_clock::now();
|
||||||
|
while (std::chrono::steady_clock::now() - start_time < duration) {
|
||||||
|
rclcpp::spin_some(test_node_);
|
||||||
|
if (final_grade_determinator_) {
|
||||||
|
rclcpp::spin_some(final_grade_determinator_);
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(10ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<rclcpp::Node> test_node_;
|
||||||
|
std::shared_ptr<FinalGradeDeterminator> final_grade_determinator_;
|
||||||
|
rclcpp::Subscription<g2_2025_interfaces::msg::Student>::SharedPtr student_subscriber_;
|
||||||
|
rclcpp::Publisher<g2_2025_interfaces::msg::Exam>::SharedPtr exam_publisher_;
|
||||||
|
rclcpp::Service<g2_2025_interfaces::srv::Exams>::SharedPtr grade_calculator_service_;
|
||||||
|
|
||||||
|
std::vector<g2_2025_interfaces::msg::Student> received_student_messages_;
|
||||||
|
std::vector<g2_2025_interfaces::srv::Exams::Request> service_requests_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(FinalGradeDeterminatorTest, ConstructorTest) {
|
||||||
|
ASSERT_NO_THROW({
|
||||||
|
create_final_grade_determinator();
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_NE(final_grade_determinator_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FinalGradeDeterminatorTest, ExamCollectionTest) {
|
||||||
|
create_final_grade_determinator();
|
||||||
|
spin_some_time(500ms);
|
||||||
|
|
||||||
|
const std::string student_name = "Test Student";
|
||||||
|
const std::string course_name = "Test Course";
|
||||||
|
std::vector<int> grades = {80, 85, 90, 75, 95};
|
||||||
|
|
||||||
|
// Send 5 exam results (default collection amount)
|
||||||
|
for (const auto& grade : grades) {
|
||||||
|
auto msg = std::make_shared<g2_2025_interfaces::msg::Exam>();
|
||||||
|
msg->student_name = student_name;
|
||||||
|
msg->course_name = course_name;
|
||||||
|
msg->result = grade;
|
||||||
|
msg->timestamp = test_node_->now();
|
||||||
|
|
||||||
|
exam_publisher_->publish(*msg);
|
||||||
|
spin_some_time(50ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_some_time(1s);
|
||||||
|
|
||||||
|
// Verify service request was made
|
||||||
|
ASSERT_FALSE(service_requests_.empty());
|
||||||
|
EXPECT_EQ(service_requests_.back().student_name, student_name);
|
||||||
|
EXPECT_EQ(service_requests_.back().course_name, course_name);
|
||||||
|
EXPECT_EQ(service_requests_.back().exam_grades, grades);
|
||||||
|
|
||||||
|
// Verify student message was published
|
||||||
|
ASSERT_FALSE(received_student_messages_.empty());
|
||||||
|
EXPECT_EQ(received_student_messages_.back().student_name, student_name);
|
||||||
|
EXPECT_EQ(received_student_messages_.back().course_name, course_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FinalGradeDeterminatorTest, PartialExamCollectionTest) {
|
||||||
|
create_final_grade_determinator();
|
||||||
|
spin_some_time(500ms);
|
||||||
|
|
||||||
|
// Send only 3 exam results (less than required 5)
|
||||||
|
const std::string student_name = "Test Student";
|
||||||
|
const std::string course_name = "Test Course";
|
||||||
|
std::vector<int> grades = {80, 85, 90};
|
||||||
|
|
||||||
|
for (const auto& grade : grades) {
|
||||||
|
auto msg = std::make_shared<g2_2025_interfaces::msg::Exam>();
|
||||||
|
msg->student_name = student_name;
|
||||||
|
msg->course_name = course_name;
|
||||||
|
msg->result = grade;
|
||||||
|
msg->timestamp = test_node_->now();
|
||||||
|
|
||||||
|
exam_publisher_->publish(*msg);
|
||||||
|
spin_some_time(50ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_some_time(1s);
|
||||||
|
|
||||||
|
// Verify no service request was made yet
|
||||||
|
EXPECT_TRUE(service_requests_.empty());
|
||||||
|
// Verify no student message was published
|
||||||
|
EXPECT_TRUE(received_student_messages_.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FinalGradeDeterminatorTest, MultipleStudentsTest) {
|
||||||
|
create_final_grade_determinator();
|
||||||
|
spin_some_time(500ms);
|
||||||
|
|
||||||
|
std::vector<std::string> students = {"Alice", "Bob"};
|
||||||
|
const std::string course_name = "Test Course";
|
||||||
|
std::vector<int> grades = {80, 85, 90, 75, 95};
|
||||||
|
|
||||||
|
// Send complete set of grades for each student
|
||||||
|
for (const auto& student : students) {
|
||||||
|
for (const auto& grade : grades) {
|
||||||
|
auto msg = std::make_shared<g2_2025_interfaces::msg::Exam>();
|
||||||
|
msg->student_name = student;
|
||||||
|
msg->course_name = course_name;
|
||||||
|
msg->result = grade;
|
||||||
|
msg->timestamp = test_node_->now();
|
||||||
|
|
||||||
|
exam_publisher_->publish(*msg);
|
||||||
|
spin_some_time(50ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_some_time(1s);
|
||||||
|
|
||||||
|
// Verify service requests were made for both students
|
||||||
|
ASSERT_EQ(service_requests_.size(), 2);
|
||||||
|
// Verify student messages were published for both students
|
||||||
|
ASSERT_EQ(received_student_messages_.size(), 2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user