Using known files in tests and benchmarks

I want to run tests and benchmarks against a pre existing datasource. All the data is stored in a directory inside my project folder. What is the best way to use this directory in my tests and benchmarks?

This is what I am currently doing:

let path: PathBuf = env::current_exe().unwrap()
    .parent().unwrap()
    .parent().unwrap()
    .parent().unwrap()
    .parent().unwrap()
    .join("data");

I feel like this is a fragile and ugly solution. Is there a better way of doing this?

It sounds like you might want to supply the path as an argument or configuration parameter in some way.

You can also iteratively go up until you find something called data.

How can I supply an argument or configuration to tests and benchmarks?

You can create a file or use an environment variable.

Wouldn't creating a config file have the same problem?

Probably yes. An alternative is to use the current directory instead of executable location as base path.

Is there no way to get the absolute path to the base of the project at compile time? For example through a macro?

If the data is small enough to fit in memory, you can use include_bytes!() to embed it in the benchmark executable. The path will be relative to the source file, so it's usually more reliable.

You can check environment variables set by Cargo. Specifically, CARGO_MANIFEST_DIR.

2 Likes

For a real-world example of this, have a look at the integration tests for the gcode crate.

I've stored a bunch of example gcode programs under tests/data/ and smoke_test.rs uses
concat!() and env!("CARGO_MANIFEST_DIR") to construct the path passed to include_str!() for embedding the file contents in the test binary.

Unfortunately my tests just a large amount of files so it wouldn't be practical to use include_str!() or include_bytes!(), but I will definitely look into the environment variables.

Shameless plug: I created a crate called include-dir-macro that lets you include the contents out a large number of files at compile time. It's not perfect, but it should do what you need.

@cliff That crate looks interesting. I might actually have I use case for that outside of testing.

1 Like

You can figure out fixture's filename using env!("CARGO_MANIFEST_DIR") and some_path_buf.join(), so why not just read the data with std::fs::File like a normal file?

To add to this, another alternative is the include_dir crate. I believe that both use include_bytes!() to embed directory tree's contents into the test binary at compile time though, which may or may not work for your use case.

Yes, I have moved to using env!("CARGO_MANIFEST_DIR") instead of env::current_exe() and just reading the files. Thanks for the help!

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.