Skills Plugins MCP Prompt Model 博客 我的中心

rust-testing

Patrones de pruebas en Rust incluyendo pruebas unitarias, de integración, async, basadas en propiedades, mocking y cobertura. Sigue la metodología TDD.

DeepseekModel 官方收录技能 质量 优秀 · 90 v1.0.0

获取

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-rust-testing-skill-md&format=skill
下载 .skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
name rust-testing description Patrones de pruebas en Rust incluyendo pruebas unitarias, de integración, async, basadas en propiedades, mocking y cobertura. Sigue la metodología TDD. origin ECC Patrones de Pruebas Rust Patrones completos de pruebas en Rust para escribir pruebas confiables y mantenibles siguiendo la metodología TDD. Cuándo Usar Escribir nuevas funciones, métodos o traits en Rust Agregar cobertura de pruebas a código existente Crear benchmarks para código con requisitos de rendimiento Implementar pruebas basadas en propiedades para validación de entrada Seguir el flujo de trabajo TDD en proyectos Rust Cómo Funciona Identificar el código objetivo — Encontrar la función, trait o módulo a probar Escribir una prueba — Usar #[test] en un módulo #[cfg(test)] , rstest para pruebas parametrizadas, o proptest para pruebas basadas en propiedades Mockear dependencias — Usar mockall para aislar la unidad bajo prueba Ejecutar pruebas (ROJO) — Verificar que la prueba falla con el error esperado Implementar (VERDE) — Escribir el código mínimo para que pase Refactorizar — Mejorar mientras se mantienen las pruebas en verde Verificar cobertura — Usar cargo-llvm-cov, objetivo 80%+ Flujo de Trabajo TDD en Rust El Ciclo ROJO-VERDE-REFACTORIZAR ROJO → Escribir primero una prueba que falle VERDE → Escribir el código mínimo para que pase REFACTORIZAR → Mejorar el código manteniendo las pruebas en verde REPETIR → Continuar con el siguiente requisito TDD Paso a Paso en Rust // ROJO: Escribir la prueba primero, usar todo!() como placeholder pub fn add (a: i32 , b: i32 ) -> i32 { todo!() } #[cfg(test)] mod tests { use super::*; #[test] fn test_add () { assert_eq! ( add ( 2 , 3 ), 5 ); } } // cargo test → panic en 'not yet implemented' // VERDE: Reemplazar todo!() con implementación mínima pub fn add (a: i32 , b: i32 ) -> i32 { a + b } // cargo test → PASS, luego REFACTORIZAR manteniendo pruebas en verde Pruebas Unitarias Organización de Pruebas a Nivel de Módulo // src/user.rs pub struct User { pub name: String , pub email: String , } impl User { pub fn new (name: impl Into < String >, email: impl Into < String >) -> Result < Self , String > { let email = email. into (); if !email. contains ( '@' ) { return Err ( format! ( "invalid email: {email}" )); } Ok ( Self { name: name. into (), email }) } pub fn display_name (& self ) -> & str { & self .name } } #[cfg(test)] mod tests { use super::*; #[test] fn creates_user_with_valid_email () { let user = User:: new ( "Alice" , "alice@example.com" ). unwrap (); assert_eq! (user. display_name (), "Alice" ); assert_eq! (user.email, "alice@example.com" ); } #[test] fn rejects_invalid_email () { let result = User:: new ( "Bob" , "not-an-email" ); assert! (result. is_err ()); assert! (result. unwrap_err (). contains ( "invalid email" )); } } Macros de Aserción assert_eq! ( 2 + 2 , 4 ); // Igualdad assert_ne! ( 2 + 2 , 5 ); // Desigualdad assert! ( vec! [ 1 , 2 , 3 ]. contains (& 2 )); // Booleano assert_eq! (value, 42 , "expected 42 but got {value}" ); // Mensaje personalizado assert! (( 0.1_f64 + 0.2 - 0.3 ). abs () < f64 ::EPSILON); // Comparación de flotantes Pruebas de Errores y Panics Probar Retornos de Result #[test] fn parse_returns_error_for_invalid_input () { let result = parse_config ( "}{invalid" ); assert! (result. is_err ()); // Verificar variante de error específica let err = result. unwrap_err (); assert! (matches!(err, ConfigError:: ParseError (_))); } #[test] fn parse_succeeds_for_valid_input () -> Result <(), Box < dyn std::error::Error>> { let config = parse_config ( r#"{"port": 8080}"# )?; assert_eq! (config.port, 8080 ); Ok (()) // La prueba falla si algún ? retorna Err } Probar Panics #[test] #[should_panic] fn panics_on_empty_input () { process (&[]); } #[test] #[should_panic(expected = "index out of bounds" )] fn panics_with_specific_message () { let v : Vec < i32 > = vec! []; let _ = v[ 0 ]; } Pruebas de Integración Estructura de Archivos my_crate/ ├── src/ │ └── lib.rs ├── tests/ # Pruebas de integración │ ├── api_test.rs # Cada archivo es un binario de prueba separado │ ├── db_test.rs │ └── common/ # Utilidades de prueba compartidas │ └── mod.rs Escribir Pruebas de Integración // tests/api_test.rs use my_crate::{App, Config}; #[test] fn full_request_lifecycle () { let config = Config:: test_default (); let app = App:: new (config); let response = app. handle_request ( "/health" ); assert_eq! (response.status, 200 ); assert_eq! (response.body, "OK" ); } Pruebas Async Con Tokio #[tokio::test] async fn fetches_data_successfully () { let client = TestClient:: new (). await ; let result = client. get ( "/data" ). await ; assert! (result. is_ok ()); assert_eq! (result. unwrap ().items. len (), 3 ); } #[tokio::test] async fn handles_timeout () { use std::time::Duration; let result = tokio::time:: timeout ( Duration:: from_millis ( 100 ), slow_operation (), ). await ; assert! (result. is_err (), "should have timed out" ); } Patrones de Organización de Pruebas Pruebas Parametrizadas con rstest use rstest::{rstest, fixture}; #[rstest] #[case( "hello" , 5)] #[case( "" , 0)] #[case( "rust" , 4)] fn test_string_length ( #[case] input: & str , #[case] expected: usize ) { assert_eq! (input. len (), expected); } // Fixtures #[fixture] fn test_db () -> TestDb { TestDb:: new_in_memory () } #[rstest] fn test_insert (test_db: TestDb) { test_db. insert ( "key" , "value" ); assert_eq! (test_db. get ( "key" ), Some ( "value" . into ())); } Helpers de Prueba #[cfg(test)] mod tests { use super::*; /// Crea un usuario de prueba con valores predeterminados sensatos. fn make_user (name: & str ) -> User { User:: new (name, & format! ( "{name}@test.com" )). unwrap () } #[test] fn user_display () { let user = make_user ( "alice" ); assert_eq! (user. display_name (), "alice" ); } } Pruebas Basadas en Propiedades con proptest Pruebas de Propiedades Básicas use proptest::prelude::*; proptest! { #[test] fn encode_decode_roundtrip (input in ".*" ) { let encoded = encode (&input); let decoded = decode (&encoded). unwrap (); assert_eq! (input, decoded); } #[test] fn sort_preserves_length ( mut vec in prop::collection:: vec (any::< i32 >(), 0 .. 100 )) { let original_len = vec. len (); vec. sort (); assert_eq! (vec. len (), original_len); } #[test] fn sort_produces_ordered_output ( mut vec in prop::collection:: vec (any::< i32 >(), 0 .. 100 )) { vec. sort (); for window in vec. windows ( 2 ) { assert! (window[ 0 ] <= window[ 1 ]); } } } Estrategias Personalizadas use proptest::prelude::*; fn valid_email () -> impl Strategy <Value = String > { ( "[a-z]{1,10}" , "[a-z]{1,5}" ) . prop_map (|(user, domain)| format! ( "{user}@{domain}.com" )) } proptest! { #[test] fn accepts_valid_emails (email in valid_email ()) { assert! (User:: new ( "Test" , &email). is_ok ()); } } Mocking con mockall Mocking Basado en Traits use mockall::{automock, predicate::eq}; #[automock] trait UserRepository { fn find_by_id (& self , id: u64 ) -> Option <User>; fn save (& self , user: &User) -> Result <(), StorageError>; } #[test] fn service_returns_user_when_found () { let mut mock = MockUserRepository:: new (); mock. expect_find_by_id () . with ( eq ( 42 )) . times ( 1 ) . returning (|_| Some (User { id: 42 , name: "Alice" . into () })); let service = UserService:: new ( Box :: new (mock)); let user = service. get_user ( 42 ). unwrap (); assert_eq! (user.name, "Alice" ); } #[test] fn service_returns_none_when_not_found () { let mut mock = MockUserRepository:: new (); mock. expect_find_by_id () . returning (|_| None ); let service = UserService:: new ( Box :: new (mock)); assert! (service. get_user ( 99 ). is_none ()); } Pruebas de Documentación Documentación Ejecutable /// Suma dos números. /// /// # Examples /// /// ``` /// use my_crate::add; /// /// assert_eq!(add(2, 3), 5); /// assert_eq!(add(-1, 1), 0); /// ``` pub fn add (a: i32 , b: i32 ) -> i32 { a + b } /// Parsea una cadena de configuración. /// /// # Errors /// /// Retorna `Err` si la entrada no es TOML válido. /// /// ```no_run /// use my_crate::parse_config; /// /// let config = parse_config(r#"port = 8080"#).unwrap(); /// assert_eq!(config.port, 8080); /// ``` /// /// ```no_run /// use my_crate::parse_config; /// /// assert!(parse_config("}{invalid").is_err());
Agent 识别该技能的关键词,点击任意一个即可复制。

该技能未提供触发词。

下载的 .skill 包内含以下字段。
字段 说明
format格式标识(skill/v1)
skill_id技能唯一 ID
name技能名称
version版本号
description技能描述
category所属分类(数组)
trigger_words触发词列表
tags标签列表
source来源标识
source_url来源链接(本页地址)
exported_at导出时间(每次下载生成)
system_prompt系统提示词正文
model_config模型参数:provider / model / temperature / max_tokens / top_p
examples示例
install_guide各平台导入说明(Coze / Dify / Claude / 自定义框架)
同一份技能可按不同平台格式导出。
.skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用 下载
.skillpro 增强格式,额外含脚本 / 工具 / 依赖 / 钩子占位 下载
.json 纯 JSON 导出,只含 system_prompt 与模型参数 下载
Coze 带 frontmatter 的 Markdown,Coze 平台导入用 下载
Dify Dify DSL,创建应用后直接导入 下载

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

验证码 --

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。