mixvideo-v2/apps/desktop/src-tauri/tests/outfit_integration_test.rs

297 lines
12 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 服装搭配功能集成测试
* 测试从图像分析到搭配推荐的完整流程
*/
#[cfg(test)]
mod outfit_integration_tests {
use std::sync::Arc;
use chrono::Utc;
use crate::data::models::outfit_analysis::{
OutfitAnalysis, CreateOutfitAnalysisRequest, AnalysisStatus, ColorHSV
};
use crate::data::models::outfit_item::{
OutfitItem, CreateOutfitItemRequest, OutfitCategory, OutfitStyle
};
use crate::data::models::outfit_matching::{
OutfitMatching, CreateOutfitMatchingRequest, MatchingType
};
use crate::data::repositories::outfit_analysis_repository::OutfitAnalysisRepository;
use crate::data::repositories::outfit_item_repository::OutfitItemRepository;
use crate::data::repositories::outfit_matching_repository::OutfitMatchingRepository;
use crate::business::services::outfit_analysis_service::OutfitAnalysisService;
use crate::business::services::outfit_item_service::OutfitItemService;
use crate::business::services::outfit_matching_service::OutfitMatchingService;
use crate::infrastructure::database::Database;
use crate::infrastructure::gemini_service::GeminiService;
/// 测试完整的服装分析流程
#[tokio::test]
async fn test_complete_outfit_analysis_workflow() {
// 创建内存数据库
let database = Arc::new(Database::new_in_memory().unwrap());
// 创建仓库
let analysis_repo = Arc::new(OutfitAnalysisRepository::new(database.clone()).unwrap());
let item_repo = Arc::new(OutfitItemRepository::new(database.clone()).unwrap());
let matching_repo = Arc::new(OutfitMatchingRepository::new(database.clone()).unwrap());
// 创建服务注意在实际测试中应该使用模拟的GeminiService
let gemini_service = Arc::new(GeminiService::new().unwrap());
let analysis_service = OutfitAnalysisService::new(analysis_repo.clone(), gemini_service);
let item_service = OutfitItemService::new(item_repo.clone());
let matching_service = OutfitMatchingService::new(matching_repo.clone(), item_repo.clone());
// 1. 创建分析记录
let analysis_request = CreateOutfitAnalysisRequest {
project_id: "test_project".to_string(),
image_path: "/test/image.jpg".to_string(),
image_name: "test_image.jpg".to_string(),
};
let analysis = analysis_service.create_analysis(analysis_request).await.unwrap();
assert_eq!(analysis.analysis_status, AnalysisStatus::Pending);
// 2. 模拟分析完成,手动创建服装单品
let item1_request = CreateOutfitItemRequest {
project_id: "test_project".to_string(),
analysis_id: Some(analysis.id.clone()),
name: "红色T恤".to_string(),
category: OutfitCategory::Top,
brand: Some("测试品牌".to_string()),
model: None,
color_primary: ColorHSV::new(0.0, 0.8, 0.9), // 红色
color_secondary: None,
styles: vec![OutfitStyle::Casual],
design_elements: vec!["纯色".to_string()],
size: None,
material: None,
price: Some(99.0),
purchase_date: None,
image_urls: vec![],
tags: vec!["夏季".to_string(), "休闲".to_string()],
notes: Some("舒适的棉质T恤".to_string()),
};
let item1 = item_service.create_item(item1_request).await.unwrap();
assert_eq!(item1.category, OutfitCategory::Top);
let item2_request = CreateOutfitItemRequest {
project_id: "test_project".to_string(),
analysis_id: Some(analysis.id.clone()),
name: "蓝色牛仔裤".to_string(),
category: OutfitCategory::Bottom,
brand: Some("测试品牌".to_string()),
model: None,
color_primary: ColorHSV::new(0.6, 0.7, 0.8), // 蓝色
color_secondary: None,
styles: vec![OutfitStyle::Casual],
design_elements: vec!["水洗".to_string()],
size: None,
material: None,
price: Some(199.0),
purchase_date: None,
image_urls: vec![],
tags: vec!["四季".to_string(), "百搭".to_string()],
notes: Some("经典款牛仔裤".to_string()),
};
let item2 = item_service.create_item(item2_request).await.unwrap();
assert_eq!(item2.category, OutfitCategory::Bottom);
// 3. 创建搭配
let matching_request = CreateOutfitMatchingRequest {
project_id: "test_project".to_string(),
matching_name: "休闲夏日搭配".to_string(),
matching_type: MatchingType::StyleConsistent,
item_ids: vec![item1.id.clone(), item2.id.clone()],
occasion_tags: vec!["日常".to_string(), "休闲".to_string()],
season_tags: vec!["夏季".to_string()],
style_description: Some("轻松休闲的夏日搭配".to_string()),
};
let matching = matching_service.create_matching(matching_request).await.unwrap();
assert_eq!(matching.matching_type, MatchingType::StyleConsistent);
assert_eq!(matching.items.len(), 2);
// 4. 验证搭配评分
assert!(matching.score_details.overall_score >= 0.0);
assert!(matching.score_details.overall_score <= 1.0);
// 5. 测试搭配推荐
let recommended_items = item_service.recommend_matching_items(
"test_project",
&item1.id,
Some(3)
).await.unwrap();
// 应该推荐item2因为它与item1风格匹配且类别互补
assert!(recommended_items.iter().any(|item| item.id == item2.id));
println!("✅ 服装分析完整流程测试通过");
}
/// 测试颜色匹配功能
#[tokio::test]
async fn test_color_matching_functionality() {
let database = Arc::new(Database::new_in_memory().unwrap());
let item_repo = Arc::new(OutfitItemRepository::new(database.clone()).unwrap());
let item_service = OutfitItemService::new(item_repo.clone());
// 创建不同颜色的服装单品
let red_item = CreateOutfitItemRequest {
project_id: "test_project".to_string(),
analysis_id: None,
name: "红色上衣".to_string(),
category: OutfitCategory::Top,
brand: None,
model: None,
color_primary: ColorHSV::new(0.0, 0.8, 0.9), // 纯红色
color_secondary: None,
styles: vec![OutfitStyle::Casual],
design_elements: vec![],
size: None,
material: None,
price: None,
purchase_date: None,
image_urls: vec![],
tags: vec![],
notes: None,
};
let blue_item = CreateOutfitItemRequest {
project_id: "test_project".to_string(),
analysis_id: None,
name: "蓝色上衣".to_string(),
category: OutfitCategory::Top,
brand: None,
model: None,
color_primary: ColorHSV::new(0.6, 0.8, 0.9), // 纯蓝色
color_secondary: None,
styles: vec![OutfitStyle::Casual],
design_elements: vec![],
size: None,
material: None,
price: None,
purchase_date: None,
image_urls: vec![],
tags: vec![],
notes: None,
};
let similar_red_item = CreateOutfitItemRequest {
project_id: "test_project".to_string(),
analysis_id: None,
name: "深红色上衣".to_string(),
category: OutfitCategory::Top,
brand: None,
model: None,
color_primary: ColorHSV::new(0.02, 0.75, 0.85), // 相似的红色
color_secondary: None,
styles: vec![OutfitStyle::Casual],
design_elements: vec![],
size: None,
material: None,
price: None,
purchase_date: None,
image_urls: vec![],
tags: vec![],
notes: None,
};
// 创建服装单品
let red = item_service.create_item(red_item).await.unwrap();
let blue = item_service.create_item(blue_item).await.unwrap();
let similar_red = item_service.create_item(similar_red_item).await.unwrap();
// 测试颜色搜索
let target_color = ColorHSV::new(0.0, 0.8, 0.9); // 红色
let matching_items = item_service.search_by_color(
"test_project",
&target_color,
0.7 // 70% 相似度阈值
).await.unwrap();
// 应该找到红色和相似红色的单品,但不包括蓝色
assert!(matching_items.iter().any(|item| item.id == red.id));
assert!(matching_items.iter().any(|item| item.id == similar_red.id));
assert!(!matching_items.iter().any(|item| item.id == blue.id));
println!("✅ 颜色匹配功能测试通过");
}
/// 测试搭配评分算法
#[tokio::test]
async fn test_outfit_scoring_algorithm() {
let database = Arc::new(Database::new_in_memory().unwrap());
let matching_repo = Arc::new(OutfitMatchingRepository::new(database.clone()).unwrap());
let item_repo = Arc::new(OutfitItemRepository::new(database.clone()).unwrap());
let matching_service = OutfitMatchingService::new(matching_repo, item_repo);
// 创建测试用的服装单品
let items = vec![
OutfitItem {
id: "1".to_string(),
project_id: "test".to_string(),
analysis_id: None,
name: "白色T恤".to_string(),
category: OutfitCategory::Top,
brand: None,
model: None,
color_primary: ColorHSV::new(0.0, 0.0, 1.0), // 白色
color_secondary: None,
styles: vec![OutfitStyle::Casual, OutfitStyle::Minimalist],
design_elements: vec![],
size: None,
material: None,
price: None,
purchase_date: None,
image_urls: vec![],
tags: vec![],
notes: None,
created_at: Utc::now(),
updated_at: Utc::now(),
},
OutfitItem {
id: "2".to_string(),
project_id: "test".to_string(),
analysis_id: None,
name: "黑色裤子".to_string(),
category: OutfitCategory::Bottom,
brand: None,
model: None,
color_primary: ColorHSV::new(0.0, 0.0, 0.0), // 黑色
color_secondary: None,
styles: vec![OutfitStyle::Casual, OutfitStyle::Minimalist],
design_elements: vec![],
size: None,
material: None,
price: None,
purchase_date: None,
image_urls: vec![],
tags: vec![],
notes: None,
created_at: Utc::now(),
updated_at: Utc::now(),
},
];
// 测试评分计算
let (score_details, suggestions) = matching_service.calculate_matching_score_and_suggestions(&items);
// 验证评分范围
assert!(score_details.color_harmony_score >= 0.0 && score_details.color_harmony_score <= 1.0);
assert!(score_details.style_consistency_score >= 0.0 && score_details.style_consistency_score <= 1.0);
assert!(score_details.overall_score >= 0.0 && score_details.overall_score <= 1.0);
// 黑白搭配应该有较高的风格一致性(都是极简风格)
assert!(score_details.style_consistency_score > 0.5);
println!("✅ 搭配评分算法测试通过");
println!(" 颜色和谐度: {:.2}", score_details.color_harmony_score);
println!(" 风格一致性: {:.2}", score_details.style_consistency_score);
println!(" 综合评分: {:.2}", score_details.overall_score);
}
}