The CUnit system is used to perform the unit testing in C, which enables for administration and execution of the tests. It covers a diverse range of assertions for testing commonly used data types and utilizes a simple architecture for creating test structures. The user’s testing code is linked with CUnit, which is designed as a static library. We may examine the performance of the C program’s tasks and functions using the CUnit test framework. Every particular task of the C program has different input circumstances and output limitations. To use the CUnit for testing the C program, we should install it first in our system. The steps for installing CUnit are outlined below.
How To Use the CUnit Framework in Ubuntu 22.04
To utilize the CUnit testing framework in our system, we need to follow the installation steps. These steps apply to the Ubuntu 22.04 system. Before installation, we first updated our system. The system required sudo privilege to get updated with the apt command.
To acquire sudo privileges, the terminal asked the authentication from the sudo user. Then, update the system packages and their dependencies, as shown below.
Now, we have installed the CUnit framework by using the following command. This command can install the libcunitl, libcunitl-doc, and libcunitl-dev packages from the package repository.
Once the CUnit installation command is executed, the user password is required. The CUnit essential packages have been installed in our Ubuntu 22.04.
Example 1
We completed the installation step of the CUnit framework in the previous section. Now, we have tested the sum and difference method to see the expected results in the following example using the CUnit testing framework.
#include <string.h>
#include <stdio.h>
#include <string.h>
#include "CUnit/Basic.h"
int init_suite(void) { return 0; }
int clean_suite(void) { return 0; }
int MySum(int a1, int b1)
{
int res1;
res1=a1+b1;
return res1;
}
int MyDiff(int a2, int b2)
{
int res2;
res2=a2-b2;
return res2;
}
void test_MySum(void)
{
CU_ASSERT(4==MySum(2,2));
CU_ASSERT(8==MySum(5,3));
CU_ASSERT(2==MySum(-2,4));
CU_ASSERT(7==MySum(0,7));
}
void test_MyDiff(void)
{
CU_ASSERT(3==MyDiff(5,2));
CU_ASSERT(-4==MyDiff(4,8));
CU_ASSERT(-7==MyDiff(-3,4));
CU_ASSERT(-9==MyDiff(0,9));
}
int main (void)
{
CU_pSuite pSuite1,pSuite2 = NULL;
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
pSuite1 = CU_add_suite("Test Suite1", init_suite, clean_suite);
if (NULL == pSuite1) {
CU_cleanup_registry();
return CU_get_error();
}
if ((NULL == CU_add_test(pSuite1, "\n\nSum function Testing\n\n", test_MySum)))
{
CU_cleanup_registry();
return CU_get_error();
}
if ((NULL == CU_add_test(pSuite1, "\n\nDifference function Testing\n\n", test_MyDiff)))
{
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}
First, to generate the CUnit structure, we have inserted the CUnit library “CUnit/Basic.h” with the included keyword. This C library is for unit testing frameworks and offers a simple console output interface. Then we added two functions, “init_suite” for the initialization of the suite function and “clean_suite” for the cleanup of the suite function, to our program for testing.
Next, we constructed methods, “MySum” and “MyDiff”, to be tested by the CUnit. We have called the constructor for these functions, which holds the variables on which sum and difference operations have been performed. Next, we have established a function as “test_MySum” to test. Inside the function, we have employed the “CU_ASSERT” method, where the init expressions for the sum are assigned. Same as “test_MySum”, we have constructed the test_MyDiff function to test the expression for different operations using the “CU_ASSERT” method.
Then, we have the CUnit runner code inside the main method. Here, we have created two suites, “pSuite1” and “pSuite2”, from the “CU_pSuite” method and assigned these suites a NULL value. We have created these suites to execute the CUnit test that should be registered in the test registry. Before adding the suites to the “test_registry”, we created the registry and initialized it with the “if condition”. We have used the “CU_initialze_registry()” method for creating the registry for testing suites.
After that, we added the pSuite1 to the test registry by invoking the “CU_add_suite” method of CUnit. After that, we added our tests, “test_MySum” and “test_MyDiff”, to the specified suites by utilizing the “CU_add_test()” method. In the end, we displayed the results of the CUnit test by calling the “CU_basic_run_tests()” method and cleaned the registry once the results were displayed successfully. The error encountered while doing the CUnit tests will be thrown by the “CU_get_error()” function.
The previous CUnit test file is saved as the mytest.c file. We have executed this C file with the GCC command. We have used the -lcunit flag for CUnit test file execution. With this command, our code is compiled. Then, we executed the mytest file, and it showed the expected results of the CUnit test as all the tests were passed without any failure.
Example 2
We have another example where we have tested the two file handling methods, “fread” and “fprintf”, by the CUnit approach. We opened and closed the temporary file using the CUnit test functions. The CUnit test operations test the library functions by writing and reading from the temporary file.
#include <string.h>
#include <stdio.h>
#include <string.h>
#include "CUnit/Basic.h"
static FILE* file = NULL;
int init_suite1(void)
{
if (NULL == (file = fopen("MyFile.txt", "w+"))) {
return -1;
}
else {
return 0;
}
}
int clean_suite1(void)
{
if (0 != fclose(file)) {
return -1;
}
else {
file = NULL;
return 0;
}
}
void test_fprintf(void)
{
int x1 = 10;
if (NULL != file) {
CU_ASSERT(2 == fprintf(file, "Q\n"));
CU_ASSERT(7 == fprintf(file, "x1 = %d", x1));
}
}
void test_fread(void)
{
unsigned char buffer[20];
if (NULL != file) {
rewind(file);
CU_ASSERT(9 == fread(buffer, sizeof(unsigned char), 20, file));
CU_ASSERT(0 == strncmp(buffer, "Q\nx1 = 10", 9));
}
}
int main()
{
CU_pSuite pSuite = NULL;
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
pSuite = CU_add_suite("Suite1", init_suite1, clean_suite1);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
if ((NULL == CU_add_test(pSuite, "fprintf() function Test", test_fprintf)) ||
(NULL == CU_add_test(pSuite, "fread() function Test", test_fread)))
{
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}
Within the header file, we have defined the CUnit standard library “CUnit.h/Basic.h”. Then, we declared “file” as a pointer to the file used by the tests. Next, we have constructed the “init_suite1” function that opens the temporary file “MyFile.txt” and returns the value zero on success; otherwise, a non-zero value will be returned. To close the file, we have created the suite cleanup function, which also returns a non-zero value on failure while closing the temporary file. Otherwise, on successfully closing the temporary file, zero value is obtained. Then, we have simply implemented a function “test_fprintf” where we have inserted the data into the temporary file “MYfile.txt”. These test functions also verified the number of bytes that we attempted to write in the file.
After that, we created another function for the “test_fread” function to test the fread method. Here, we have checked that the specified characters are present in the previously written data by the “test_fprinf()” function. Then, we have the main function where the tests set up and executed are handled. We defined the “pSuite” in the main function and initialized the registry using the “CU_initialize_resgistry” test function. We have also called the “CU_add_suite” function to add the suite to the registry and added the specified tests to the suites with the help of the “CU_add_test” function.
The basic CUnit test interfaces are used in the end to display the results of the code. Note that the main function returns a “CUE_SUCCESS” upon successful execution and a different “CUnit_error” code upon unsuccessful execution.
We have run the previous code for the CUnit test, which displayed the program summary and the successful tests’ method message.
Conclusion
CUnit is a core framework that provides various user interfaces. It allows us to manage test suites, test cases, and test registries. Testing the programs and seeing the results of those tests is made easier by the user interfaces. We have covered the CUnit test framework in C with this article. We demonstrated the installation and then implemented two running programs in C language. The previous programs tested have given successful results.