Unit testing approach. Forced to pick the lesser of two evils?

⚓ Rust    📅 2025-06-19    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 55 days ago. The information described in this article may have changed.

I am writing a simple queue interface backed by a vector. For reference, the implementation looks like this:

Code (click for more details)

I need advice about how to approach writing unit tests in the "best practices" way. I am aware of two common pieces of advice for writing tests:

  1. Don't test implementation details.
  2. Tests should fail for one and only one reason.

I often find those two pieces of advice in conflict. Let's say that I want to test the remove method, if I want to comply with 1, I need to build first a queue with add to start testing remove, and possibly even use iter to check that the queue is correct. Now my test violates 2 because I'm using add and iter to test remove and they may fail for their own bugs.

A similar argument can be said about complying with 2. If I want my tests to fail for only one reason I need to build a suitable initial state for my ArrayQueue in order to start testing remove, so to avoid using add I need to write implementation details in my test, like writing an initial value for storage: vec![Some(2), None, Some(0), Some(1)]. This will force me to rewrite the tests if I change the implementation in the future.

In short, I need advice about how to approach unit testing, and in particular how to comply with 1 and 2 at the same time, if that is even possible. Needles to say, I'm by no means a seasoned software engineer. Any advice will be much appreciated.

3 posts - 3 participants

Read full topic

🏷️ rust_feed