armature_testing/lib.rs
1//! Testing utilities for Armature framework.
2//!
3//! This crate provides comprehensive testing tools for Armature applications.
4//!
5//! ## Features
6//!
7//! - ๐งช **TestApp** - Integration test builder
8//! - ๐ก **TestClient** - HTTP test client
9//! - ๐ญ **MockService** - Service mocking
10//! - ๐๏ธ **Spy** - Manual call recording (see [`Spy`] - it records what you tell
11//! it to; it does not intercept calls to the value it wraps)
12//! - โ
**Assertions** - Fluent test assertions
13//! - ๐๏ธ **Integration Helpers** - Database setup/teardown
14//! - ๐ณ **Docker Containers** - Docker-based testing
15//! - ๐ **Load Testing** - Performance test utilities
16//! - ๐ **Contract Testing** - Pact/consumer-driven contracts
17//!
18//! ## Quick Start
19//!
20//! ```no_run
21//! use armature_testing::*;
22//! use armature_core::{HttpRequest, HttpResponse, Error};
23//!
24//! # tokio_test::block_on(async {
25//! // Create a test app
26//! let app = TestAppBuilder::new()
27//! .with_route("/hello", |_req| async {
28//! Ok(HttpResponse::ok().with_body(b"Hello!".to_vec()))
29//! })
30//! .build();
31//!
32//! // Make test requests
33//! let client = app.client();
34//! let response = client.get("/hello").await;
35//! assert_eq!(response.status(), Some(200));
36//! assert_eq!(response.body_string(), Some("Hello!".to_string()));
37//! # });
38//! ```
39//!
40//! ## Testing Controllers
41//!
42//! ```no_run
43//! use armature_testing::*;
44//! use armature_core::{HttpRequest, HttpResponse, Error};
45//!
46//! # tokio_test::block_on(async {
47//! let app = TestAppBuilder::new()
48//! .with_route("/api/users", |_req| async {
49//! Ok(HttpResponse::ok().with_json(&serde_json::json!({
50//! "users": ["Alice", "Bob"]
51//! }))?)
52//! })
53//! .build();
54//!
55//! let client = app.client();
56//! let response = client.get("/api/users").await;
57//! let json: serde_json::Value = response.body_json().unwrap();
58//! assert_eq!(json["users"][0], "Alice");
59//! # });
60//! ```
61//!
62//! ## Mock Services
63//!
64//! ```
65//! use armature_testing::MockService;
66//!
67//! // Create a mock service
68//! let mock = MockService::<String>::new();
69//! mock.record_call("get_user");
70//!
71//! // Verify calls
72//! assert_eq!(mock.call_count(), 1);
73//! assert!(mock.was_called("get_user"));
74//! ```
75//!
76//! ## Assertions
77//!
78//! ```
79//! use armature_testing::*;
80//! use armature_core::HttpResponse;
81//!
82//! let response = HttpResponse::ok()
83//! .with_header("Content-Type".to_string(), "application/json".to_string())
84//! .with_body(b"{\"status\":\"ok\"}".to_vec());
85//!
86//! let test_response = TestResponse::Success(response);
87//!
88//! // Assert status
89//! assert_status(&test_response, 200);
90//!
91//! // Assert headers
92//! assert_header(&test_response, "Content-Type", "application/json");
93//! ```
94//!
95//! ## Integration Testing with Database
96//!
97//! ```rust,ignore
98//! use armature_testing::integration::*;
99//! use std::sync::Arc;
100//!
101//! // Implement DatabaseTestHelper for your database
102//! struct MyDbHelper;
103//!
104//! #[async_trait]
105//! impl DatabaseTestHelper for MyDbHelper {
106//! async fn setup(&self) -> Result<(), IntegrationTestError> {
107//! // Create tables, seed data
108//! Ok(())
109//! }
110//!
111//! async fn teardown(&self) -> Result<(), IntegrationTestError> {
112//! // Clean up
113//! Ok(())
114//! }
115//! }
116//!
117//! // Use in tests
118//! let fixture = TestFixture::new(Arc::new(MyDbHelper));
119//! fixture.run_test(|| async {
120//! // Your test code
121//! Ok(())
122//! }).await?;
123//! ```
124//!
125//! ## Docker Test Containers
126//!
127//! ```rust,ignore
128//! use armature_testing::docker::*;
129//!
130//! // Start Postgres container
131//! let config = PostgresContainer::config("testdb", "user", "pass");
132//! let mut container = DockerContainer::new(config);
133//! container.start().await?;
134//!
135//! // Run tests...
136//!
137//! // Container automatically stops on drop
138//! ```
139//!
140//! ## Load Testing
141//!
142//! ```rust,ignore
143//! use armature_testing::load::*;
144//!
145//! let config = LoadTestConfig::new(10, 1000); // 10 concurrent, 1000 requests
146//! let runner = LoadTestRunner::new(config, || async {
147//! // Your test code
148//! Ok(())
149//! });
150//!
151//! let stats = runner.run().await?;
152//! stats.print();
153//! ```
154//!
155//! ## Contract Testing
156//!
157//! ```rust,ignore
158//! use armature_testing::contract::*;
159//!
160//! // Create a contract
161//! let request = ContractRequest::new(ContractMethod::Get, "/api/users/1");
162//! let response = ContractResponse::new(200)
163//! .with_body(serde_json::json!({"id": 1, "name": "Alice"}));
164//!
165//! let mut builder = ContractBuilder::new("Frontend", "Backend");
166//! builder.add_interaction(ContractInteraction::new(
167//! "get user by ID",
168//! request,
169//! response,
170//! ));
171//!
172//! let contract = builder.build();
173//!
174//! // Save contract
175//! let manager = ContractManager::new(PathBuf::from("./pacts"));
176//! manager.save(&contract)?;
177//! ```
178
179mod assertions;
180mod mock;
181mod test_app;
182mod test_client;
183mod test_container;
184
185// New modules
186pub mod contract;
187pub mod docker;
188pub mod integration;
189pub mod load;
190
191pub use assertions::{assert_header, assert_json, assert_status};
192pub use mock::{MockController, MockProvider, MockService, Spy};
193pub use test_app::{TestApp, TestAppBuilder};
194pub use test_client::{TestClient, TestResponse};
195pub use test_container::TestContainer;
196
197// Re-export common testing utilities
198pub use tokio::test as tokio_test;
199
200/// Prelude for common imports.
201///
202/// ```
203/// use armature_testing::prelude::*;
204/// ```
205pub mod prelude {
206 pub use crate::assertions::{assert_header, assert_json, assert_status};
207 pub use crate::mock::{MockController, MockProvider, MockService};
208 pub use crate::test_app::{TestApp, TestAppBuilder};
209 pub use crate::test_client::{TestClient, TestResponse};
210 pub use crate::test_container::TestContainer;
211
212 // Integration testing
213 pub use crate::integration::{DatabaseTestHelper, IntegrationTestError, TestFixture};
214
215 // Docker testing
216 pub use crate::docker::{ContainerConfig, DockerContainer};
217
218 // Load testing
219 pub use crate::load::{LoadTestConfig, LoadTestRunner, LoadTestStats};
220
221 // Contract testing
222 pub use crate::contract::{
223 Contract, ContractBuilder, ContractInteraction, ContractManager, ContractMethod,
224 ContractRequest, ContractResponse,
225 };
226}
227
228#[cfg(test)]
229mod tests {
230 #[test]
231 fn test_module_exports() {
232 // Ensure module compiles
233 }
234}