如何编写Cucumber步骤定义等待MongoDB中转换状态变为DONE
Got it, let's tackle this Cucumber step definition where we need to wait for a MongoDB status field to reach DONE without relying on a fixed sleep timer. Here's how I'd approach it:
The core idea here is to use a polling mechanism: we'll regularly check the MongoDB status field at set intervals until it hits DONE, or until we hit a maximum wait time (matching your 30-minute upper limit for large files). This avoids wasting time waiting unnecessarily if the conversion finishes early, while still accounting for long-running tasks.
Step Definition Code (Java Example)
Assuming you're using Cucumber with Java, the MongoDB Java Driver, and AssertJ for clean assertions:
import io.cucumber.java.en.Then; import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import org.bson.Document; import java.time.Duration; import java.time.Instant; public class ConversionTaskSteps { // Match your worst-case conversion time private static final Duration MAX_WAIT_DURATION = Duration.ofMinutes(30); // Adjust based on how frequently status updates are expected private static final Duration POLL_INTERVAL = Duration.ofSeconds(10); @Then("转换状态必须为DONE") public void waitForConversionCompletion() { Instant startTime = Instant.now(); MongoCollection<Document> taskCollection = MongoClients.create() .getDatabase("your_database_name") .getCollection("conversion_tasks"); while (Duration.between(startTime, Instant.now()).compareTo(MAX_WAIT_DURATION) < 0) { // Fetch the task using your user context (adjust query to match your document structure) Document conversionTask = taskCollection.find( new Document("user_id", getCurrentUserIdFromContext()) ).first(); String currentStatus = conversionTask.getString("status"); if ("DONE".equals(currentStatus)) { return; // Exit early once status is correct } // Wait before next check try { Thread.sleep(POLL_INTERVAL.toMillis()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Status polling was interrupted", e); } } // If we exit the loop without returning, the task never completed throw new AssertionError( String.format("Conversion failed to reach DONE status within %d minutes", MAX_WAIT_DURATION.toMinutes()) ); } // Helper to pull user ID from your shared Given step context private String getCurrentUserIdFromContext() { // Replace with your actual logic to fetch the user ID stored in the scenario context return "active_user_id"; } }
Key Details to Adjust:
- Poll Interval: I used 10 seconds, but tweak this based on how often your
start conversionservice updates the status. Shorter intervals mean faster detection of completion but more database calls; longer intervals reduce load but add a small delay after the task finishes. - User Context Integration: Make sure
getCurrentUserIdFromContext()correctly retrieves the user (or task) identifier from theGiven 用户上下文step. You'll likely use a shared scenario context object to pass this data between steps. - Max Wait Time: Set to 30 minutes to cover your longest expected conversion time. If the task exceeds this, the step fails with a clear error message.
Ruby Alternative (Cucumber + Mongoid)
If you're working with Ruby, the logic is identical—just adapted to the Ruby ecosystem:
Then("转换状态必须为DONE") do max_wait_seconds = 30 * 60 # 30 minutes poll_interval_seconds = 10 start_time = Time.now loop do conversion_task = ConversionTask.find_by(user_id: @current_user.id) break if conversion_task.status == "DONE" break if (Time.now - start_time) > max_wait_seconds sleep(poll_interval_seconds) end expect(conversion_task.status).to eq("DONE"), "Conversion did not complete within 30 minutes" end
This approach is efficient because it only checks the database when necessary, avoiding the wasted time of a fixed sleep timer for fast-completing tasks.
内容的提问来源于stack exchange,提问作者Raul_M

