📜 ⬆️ ⬇️

Automatic start of unit tests for C

I use C for scientific calculations. And in this case, it is worth thinking hard, but do you really need C?

The C language is only needed if your calculations are very critical for performance or access to hardware. In all other cases, I highly recommend high-level languages ​​like Ruby or Python (almost the standard language for scientific calculations, a lot of scientific packages of various kinds from mathematics to biology) or, better, scientific packages like Sage (add-on python with the ability to the use of symbolic calculations and a lot more, as well as the ability to connect other mathematics packages, if there are not enough Sage capabilities, right inside the Sage program; by the way, Sage was written in Habré).

For Python, if performance is important and you are not ready to lick C-code to perfection, there is Cython (whose authors are also authors of Sage), which compiles almost Python code into C-code, achieving very high performance rates.
')
So at this stage I urge you once again: think before using C for scientific or other calculations! Otherwise, let's go!

So, you still decided to use C. In this case, you need to organize a working test environment, namely:


Because what is the scientific calculation, if the code that implements it is not tested properly? Well, this is just besides the fact that with testing the development runs much faster. But in order for the speed to be really high, you need an automatic test run.

On the topic of choosing a framework for unit testing, there is a powerful thread on Stackoverflow , a post on Habré , a comparison of unit testing frameworks on Wikipedia pages and even an rspec for testing code in C and C ++ (I didn’t get started).

Of all this variety, the Google Testing Framework seemed the most pleasant to me (they also wrote about it on Habré).

The only thing that, when working with him, as a person who is not very experienced in testing C language, there were a number of problems (for example, how in Ubuntu to compile and run the damn human test ?!). This question is almost never properly covered, except for “put gtest in the project folder and follow the instructions from the README”, which, of course, is far from human, or to the instructions for older Ubuntu (older than 11.10) that do not fit Oneiric Ocelot.

The result of all my moans was the following simple text: installation on Ubuntu 11.10 comes down to sudo apt-get install libgtest-dev (or yaourt -S gtest in ArchLinux). Then in your my_app_test.cpp file you need to write something like:
 #include "gtest/gtest.h" int add(int value1, int value2) { return (value1 + value2); } TEST (AddTest, PositiveNos) { EXPECT_EQ (16, add(8, 8)); } 

Where AddTest is the name of the test group, and PositiveNos is the name of the test. EXPECT_EQ, as is almost obvious from the name, checks the value of two expressions for equality. Analogue assert 16 == 8+8 . However, ASSERT_TRUE is also in the arsenal .

Everything, the test is ready. Of course, in real life you have to do #include "my_app.h" , but in the example we’ll get by with what we have.

Running a test is the execution of the following g++ my_app_test.cpp -lgtest_main -lgtest -pthread && ./a.out .

More information in Russian can be found in the official textbook .

I will illustrate the unsuccessful test run (red)



And successful (green)



Testing is adjusted, now we need to adjust the automatic run of tests after changing the code. Otherwise, the message of this approach with unit-tests simply will not work.

For this we will use the watchr tool (popular in the Ruby environment). In order for everything to be beautiful and nice notifications were displayed, you need the libnotify library installed (for everything to be absolutely beautiful, you need to push the .watchr_images / failed.png and .watchr_images / passed.png files into the project folder).

We put ruby ​​(needed for watchr) and libnotify: sudo apt-get install ruby libnotify4 , and then install the watchr: sudo gem install watchr .

Take the watchr file from here . I will give the text of the script:
 ENV["WATCHR"] = "1" system 'clear' def run(cmd) puts(cmd) system(cmd) end def growl(result) message = result ? "OK" : "FAILED" growlnotify = `which notify-send`.chomp title = "Watchr Test Results" image = (result) ? ".watchr_images/passed.png" : ".watchr_images/failed.png" options = %("#{title}" "#{message}" -i #{File.expand_path(image)}) system %(#{growlnotify} #{options} &) end watch( '(.+)(\.c|_test\.cpp|\.h)$' ) do |md| result = run("g++ #{md[1]}_test.cpp #{md[1]}.c -lgtest_main -lgtest -pthread -o #{md[1]}_test && ./#{md[1]}_test") growl result puts ("\n\n") end 


The script is launched by a simple watchr watchr.rb : watchr watchr.rb .

Source: https://habr.com/ru/post/133315/


All Articles