19 Rustlings Tests Solution

We're going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!

Further information

Tests1.rs

// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustlings run tests1

// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail!
// Execute `rustlings hint tests1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert() {
        assert!();
    }
}

So now we're looking at tests, an important part of the development process in any language is being able to test your code. In our first exercise we see instructions that tells us to make the test compile, make the test fail, essentially to play around with the code. Let's look at our errors.

Test1.rs errors

⚠️  Compiling of exercises/tests/tests1.rs failed! Please try again. Here's the output:
error: macro requires a boolean expression as an argument
  --> exercises/tests/tests1.rs:16:9
   |
16 |         assert!();
   |         ^^^^^^^^^ boolean expression required

error: aborting due to previous error

The compiler gives us a big hint, we need to add a boolean expression. So let's try that.

Test1.rs Solution


#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert() {
        assert!(false == false); // let's add false == false
    }
}

if we add this we actually compile and pass the tests:

✅ Successfully tested exercises/tests/tests1.rs

🎉 🎉  The code is compiling, and the tests pass! 🎉 🎉

But let's see what happens when we change what's inside of the assert! as we are told to do in our exercises. if we change our assert! to this:

assert!(false == true);

we fail and panic!

running 1 test
test tests::you_can_assert ... FAILED

successes:

successes:

failures:

---- tests::you_can_assert stdout ----
thread 'tests::you_can_assert' panicked at 'assertion failed: false == true', exercises/tests/tests1.rs:16:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

What about trying out different types

assert!(1 == 1); // this passes ✅

assert!(1); // this fails ❌

assert!("hi" == "hi"); // this passes ✅

Alright, we get the idea we need to have something to compare it, and have it be equal for it to pass, alright got it! Let's move on.

Test2.rs

// tests2.rs
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail!
// Execute `rustlings hint tests2` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert_eq() {
        assert_eq!();
    }
}

Our instructions are again similar, we need to make the code compile and pass tests.

Test2.rs Errors

Looking at the errors we can see

⚠️  Compiling of exercises/tests/tests2.rs failed! Please try again. Here's the output:
error: unexpected end of macro invocation
  --> exercises/tests/tests2.rs:12:9
   |
12 |         assert_eq!();
   |         ^^^^^^^^^^^^ missing tokens in macro arguments
   |
note: while trying to match meta-variable `$left:expr`
  --> /Users/desmo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/macros/mod.rs:37:6

Again we get a clear statement saying we have missing tokens in the macro arguments. So let's play around and see what we get.

Test2.rs Solution

#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert_eq() {
        assert_eq!(0, true);
    }
}

This fails! Let's see what the compiler says

⚠️  Compiling of exercises/tests/tests2.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
  --> exercises/tests/tests2.rs:12:9
   |
12 |         assert_eq!(0, true);
   |         ^^^^^^^^^^^^^^^^^^^ expected integer, found `bool`

Okay, so now let's try

assert_eq!(0, 0);

This compiles

✅ Successfully tested exercises/tests/tests2.rs

🎉 🎉  The code is compiling, and the tests pass! 🎉 🎉

Let's try different values

assert_eq!("hi", "hi");  ✅

assert_eq!("0", 0);  ❌

assert_eq!(true, true); ✅

assert_eq!(true, false); ❌

Similar to our last exercise, we can enter comma separated values and see what happens. We clearly. have to enter matching values or the tests fail. Great, moving on!

Test3.rs

// tests3.rs
// This test isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests whether we get the result
// we expect to get when we call `is_even(5)`.
// Execute `rustlings hint tests3` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

pub fn is_even(num: i32) -> bool {
    num % 2 == 0
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn is_true_when_even() {
        assert!();
    }

    #[test]
    fn is_false_when_odd() {
        assert!();
    }
}

Now, we finally get a function to test, it looks like we have to make the code compile and pass tests. If we look at the function we can see that it takes in an i32 and returns a bool meaning, either true or false so does that give us a hint as to what to do?

Test3.rs Errors

Let's take a look at the errors, again we see that we have an expression missing in our assert! macro, so let's fix that.

⚠️  Compiling of exercises/tests/tests3.rs failed! Please try again. Here's the output:
error: macro requires a boolean expression as an argument
  --> exercises/tests/tests3.rs:19:9
   |
19 |         assert!();
   |         ^^^^^^^^^ boolean expression required

error: macro requires a boolean expression as an argument
  --> exercises/tests/tests3.rs:24:9
   |
24 |         assert!();
   |         ^^^^^^^^^ boolean expression required

warning: unused import: `super::*`
  --> exercises/tests/tests3.rs:15:9
   |
15 |     use super::*;
   |         ^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

Test3.rs Solution

We've been playing with these tests for a couple of exercises and we can say that we've seen that we need to have matching values. So we know that we need to match a bool so let's try that..


pub fn is_even(num: i32) -> bool {
    num % 2 == 0
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn is_true_when_even() {
        assert!(true == true);
    }

    #[test]
    fn is_false_when_odd() {
        assert!(false == false);
    }
}

And there we have it! Our tests are passing and our code is compiling.

running 2 tests
test tests::is_true_when_even ... ok

✅ Successfully tested exercises/tests/tests3.rs

🎉 🎉  The code is compiling, and the tests pass! 🎉 🎉

Conclusion

Congratulations, you've just taken a quick look into the world of testing in Rust! From understanding how to make a test compile to making it pass or fail intentionally. You've also explored how to handle different types and expressions within the assert! and assert_eq! macros.

Key Takeaways:

  1. Boolean Expressions: The assert! macro requires a boolean expression. If the expression evaluates to true, the test passes; otherwise, it fails and panics.
  2. Matching Types: The assert_eq! macro expects two values of the same type. If they are equal, the test passes; otherwise, it fails.
  3. Function Testing: We also looked at how to test a custom function (is_even) using the assert! macro. This gave us a practical example of how testing integrates into real-world code.
  4. Error Messages: Paying attention to compiler error messages can provide valuable hints for resolving issues in your tests.
  5. Exploration: Don't be afraid to experiment. Changing the values and types in your tests can offer additional insights into how Rust's testing framework operates.

Testing is a critical part of software development that ensures your code behaves as expected. It's a safety net that allows you to make changes to your code with confidence. As you continue your journey with Rust, you'll find that the language's robust testing framework is a powerful ally in writing reliable, robust software.

So, the next time you're writing code in Rust, remember: a test today can prevent a bug tomorrow. Happy coding!