Unit testing is an integral part of the development process. As a project grows, it can become more interconnected and unstable, and putting down unit tests for some important features can help provide confidence that those features remain unimpacted as you develop other parts of your codebase. Now with Q# unit tests, you can leverage this design pattern to help manage your Q# coding projects. Let’s look at how unit tests in Q# work.
Any operation or function can be marked as a unit test, so long as it doesn’t take any arguments and returns Unit. To mark such an operation or function as a unit test, we decorate it with the @Test attribute. This new attribute is defined in the Microsoft.Quantum.Diagnostics namespace, and takes one string argument, which is the name of the execution target the test is to be run against. Some built-in simulator targets that can be used here are “QuantumSimulator”, “ToffoliSimulator”, and “ResourcesEstimator”. Q# also supports other custom targets if we provide their fully qualified name. If we want one test to be run against multiple execution targets, we can decorate the test with multiple @Test attributes. Here is an example unit test with several execution targets:
This Q# testing framework is backed using Xunit and C#. Each test-target pair will be represented as its own test in Xunit, allowing tests for specific targets to be run independently. Here is an example of how it looks in the Visual Studio Test Explorer:
You’ll notice that the tests have some Xunit traits attached to them. The “Target” trait will have as its value the unqualified name of the execution target for the test, and the “Name” trait will have as its value the name of the unit test as it appears in the Q# source code. These traits can be used to filter specific groups of tests to run. Here are some examples for command line usage:
- To run all the targets for a specific test:
$> dotnet test --filter="Name = MyUnitTest"
- Or multiple specific tests:
$> dotnet test --filter="Name = MyUnitTest | MyOtherTest"
- To run all tests for a specific target:
$> dotnet test --filter="Target = QuantumSimulator"
- Or multiple specific targets:
$> dotnet test --filter="Target = QuantumSimulator | ToffoliSimulator"
- Multiple traits may be combined to run specific tests on specific targets:
$> dotnet test --filter="Name = MyUnitTest & Target = QuantumSimulator"
For a full description of the syntax used for filtering, see the documentation.
In addition to providing us with the @Test attribute, allowing us to make unit tests, the Microsoft.Quantum.Diagnostics namespace contains several testing operations and functions that can be very useful inside of unit tests. Here are some particularly useful utilities:
- The Fact function is a generic check that some Boolean expression evaluates to true, otherwise it throws an error with the given message. This is a great general-purpose tool for checking a variety of things inside a unit test.
- Certain simulators, such as the “QuantumSimulator”, are capable of providing extra data about the qubits being simulated. When targeting such simulators, the DumpMachine and DumpRegister functions can be used for getting this data. The DumpMachine will provide information about the state of all the qubits in the simulation, while the DumpRegister can be used to provide information about specific qubits.
- When using the “using” keyword to allocate qubits for your program, the qubits must be returned to the Zero state when you are done using them. The AssertAllZero operation can be useful for checking if your qubits are ready to be returned to the system.
- When developing algorithms, it is often useful to start with an alternative implementation of some well-defined behavior, from which you can add in new logic that suits your needs. The AssertOperationsEqualInPlace operation allows you to test two different quantum operation implementations to see if they have the same behavior with all input qubit states.
For a full description of the diagnostics utilities provided by the namespace, see the Microsoft.Quantum.Diagnostics namespace documentation.
Writing unit test can be an invaluable tool to help manage your codebases as they grow in size and complexity. These Q# features and tools aim to make writing and maintaining unit test more intuitive and straightforward. By using Q# unit tests, you can more confidently make changes to your projects and focus on writing awesome quantum algorithms!
This post is part of Q# Advent Calendar 2019.
0 comments