How to import a file in tests?

As discussed in a related thread, zig test isn’t integrated with the build system. As things stand, I suggest doing all things Zig through zig build.

Not exactly. What does work is making your file into a module in the build system, then importing it.

Say you want test code in ./test/test-code.zig and it needs a module rooted in ./src/some-module.zig. You can set this up like so in build.zig:

const some_module = b.addModule("some-module", .{
    .root_source_file = b.path("src/some-module.zig"),
    // ...
};

const unit_tests = b.addTest(.{
    .root_source_file = b.path("test/test-code.zig"),
    // ...
};

unit_tests.root_module.addImport("some-module", some-module);

Then test-code.zig can call @import("some-module"). If you end up moving things around, you have to update the .root_source_file, but everything else should keep working.

This isn’t specific to tests, it works for any case where you want to organize code into parallel directories. If you need to reach into an entire parallel directory/repo, and don’t want to play host-and-fetch right away, you can do that with build.zig.zon as well:

.dependencies = .{
    .other-repo = .{ 
        .path = "../in-parallel",
    },
},

You wouldn’t want to distribute code like this, but for local work it’s fine, and swapping out a .url and .hash when it’s time is easy.

This is a bit more work up front than a .. path, but scales better, for instance the module can be used in another project with zig fetch or using a .path in the build.zig.zon for local development.

Something to watch out for is that you can’t import two modules which both import the same file by path. That can always be solved by making the mutual dependency a module in the above fashion, among other ways, it’s just something to be aware of.

1 Like