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
.