I am working on a hobby project mainly to learn cpp unit testing and database programming. However I am a little bit lost & confused about how should I write my code for proper testing. I tend to write a lot of void functions for my cpp projects. But now I can not figure out how should I test those functions. I have been succeeded in testing non-void functions cause they return something which can be easily tested against a value.
Ami I doing things in an unprofessional way? Should I avoid void functions as much as possible so that I can test those functions ? Or I am missing something ? For example how would I be able to test this function -
database.cpp
#include "database.hpp"
#include <sqlite3.h>
#include <iostream>
#include "spdlog/sinks/basic_file_sink.h"
// Creating the logging object
auto logger = spdlog::basic_logger_mt("appnotex", "../data/appnotexlog");
void Database::createDb(const char *dbname) {
// Creating the database file
sqlite3 *datadb;
int status = sqlite3_open(dbname, &datadb);
// checking for errors
if (status == SQLITE_OK) {
logger->info("------------ New Session ----------");
logger->info("Connected to Database Successfully");
} else {
std::string errorMessage = sqlite3_errmsg(datadb);
logger->info("Error: " + errorMessage);
}
If Needed
I am using Google Test framework
My whole project code hosted - here
Update
I have tried this one is this approach of testing the above method correct ?
databaseTest.cpp
TEST(DatabaseTest, createDbTest) {
const char *dbfilename = "../data/test/data.db";
const char *tbname = "DataTest";
Database *db = new Database();
std::ifstream dbfile("../data/test/data.db");
bool ok = false;
if (!dbfile.is_open())
ok = false;
else
ok = true;
EXPECT_TRUE(ok);
}
The problem is not so much in the function returning void. Think about how it signals errors and make sure all cases (success and failures) are tested, simple as that.
However, I don't see any error signalling at all there, apart from logging it. As a rule of thumb, logging should only be used for post-mortem research and the like. So, if logging completely fails, your program can still run correctly. That means, nothing internally depends on it and it is not a suitable error handling/signalling mechanism.
Now, there are basically three ways to signal errors:
Return values. Typically used in C code and sometimes used in C++ as well. With void return, that's not an option, and that is probably the source of your question.
Exceptions. You could throw std::runtime_error("DB connect failed"); and delegate handling it to the calling code.
Side effects. You could store the connection state in your Database instance. For completeness, using a global errno is also possible, but not advisable.
In any case, all three ways can be exercised and verified in unit tests.
Related
Suppose I have this in a custom Stack implementation:
void Pop (Stack & s) {
assert (!isEmpty(s));
// implementation details of popping omitted
}
Suppose I want to catch bad client uses like popping an empty stack. "Assert" is great until you compile the production version and disable it via the NDEBUG flag. What's the most professional way of dying gracefully if you detect an unrecoverable error, assuming that you are going to turn off assertions eventually?
Yes, I know there are a bunch of options: use "exit"; change the function to return a C-like error code; use C++ exception handling; just ignore the offending operation (make bad calls into a no-op); implement a personal version assert called something else that won't get turned off, etc.
What the "most pro" thing to do here? I just want to die quickly, with a helpful message.
For fun, I created a vector instance from the standard library and popped it empty. This caused a seg fault, which might be acceptable for the standard library, but I want to catch and report such a problem before dying.
It is often used self defined assert macro with logging in production code. For example,
#define MYCOMPANY_ASSERT_FATAL(expression, msg, ret_val) if (!expression){ logger.fatal(msg); return ret_val;}
#define MYCOMPANY_ASSERT_WARN(...) .....
#define MYCOMPANY_ASSERT_ERROR(...) .....
Basically, the severity level of the error which should be regarded as exiting or messaging or so is dependent on your application program context layer. In short, some_lib_func() couldn't decide to exit an own process in most cases. That's why some_lib_func() should propagate the error information to caller. For example,
// library or middle module func couldn't decide to handle own application process, so after only logging return to caller
bool read_csv(double& val) {
double val = 0;
bool ret = parse_csv_from_file(val);
MYCOMPANY_ASSERT_ERROR(ret, "failed to parse_csv_from_file", false);
// return to caller with logging and error info(true/false here)
....
....
}
// application layer and need to handle for error which should be continue or message for user..
bool show_weather_in_foreign_country() {
bool ret = read_csv();
if (!ret) {
show_error_message();
}
// in this case read_csv error is trivial and you want to continue to process with proper message
...
}
In this case, showing weather is considered as trivial process in your application and you don't want to exit a whole application if error, so after showing a appropriate message and continue to process. In the other hand, another case below is critical, despite using the same function of read_csv.
// application layer and need to handle for error which should be continue or message for user..
bool send_your_account_balance_in_securiities_to_your_wife() {
double val = 0;
bool ret = read_csv(val);
MYCOMPANY_ASSERT_FATAL(ret, "critical in my account balance", false);
// in this application context, the failure of read_csv is critical and never continue to process
// and return to caller. Caller should probably exit an own application
send_email_your_wife(val);
// if send 0$ with some kind of mistake to you wife, she might die or kill you ...
...
}
Therefore, preparing some of defined macro for propagating error and logging is so useful and make your code simple and safe, and then you need to use them properly depending on your application contexts.
I'm trying to implement a very simple, local, HTTP server for my C++ application — I'm using XCode on macOS. I have to implement it from within a dynamically loaded library rather than the "main" thread of the program. I decided to try using boost::beast since another part of the application uses boost libraries already. I'm trying to implement this example, but within the context of my library, and not as part its main program.
The host application for this library calls on the following function to start a localhost server, but crashes when instantiating "acceptor":
extern "C" BASICEXTERNALOBJECT_API long startLocalhost(TaggedData* argv, long argc, TaggedData * retval) {
try {
string status;
retval->type = kTypeString;
auto const address = net::ip::make_address("127.0.0.1");
unsigned short port = static_cast<unsigned short>(std::atoi("1337"));
net::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}}; // <-- crashes on this line
tcp::socket socket{ioc};
http_server(acceptor, socket);
ioc.run();
status = "{'status':'ok', 'message':'localhost server started!'}";
retval->data.string = getNewBuffer(status);
}
catch(std::exception const& e)
{
string status;
//err_msg = "Error: " << e.what() << std::endl;
status = "{'status':'fail', 'message':'Error starting web server'}";
retval->data.string = getNewBuffer(status);
}
return kESErrOK;
}
When stepping through the code, I see that XCode reports an error when the line with tcp::acceptor ... is executed:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x783c0a3e3f22650c)
and is highlighted at the single line of code in a function in scheduler.h:
//Get the concurrency hint that was used to initialize the scheduler.
int concurrency_hint() const
{
return concurrency_hint_; //XCode halts here
}
I'm debating as to whether or not I should include a different C++ web server, like Drogon, instead of boost::beast, but I thought I would post here to see if anybody had any insight as to why the crash is happening in this case.
Update
I found a fix that is a workaround for my particular circumstances, hopefully it can help others running into this issue.
The address to the service_registry::create static factory method resolves correctly when I add ASIO_DECL in front of the methods declaration in asio/detail/service_registry.hpp.
It should look like this:
// Factory function for creating a service instance.
template <typename Service, typename Owner>
ASIO_DECL static execution_context::service* create(void* owner);
By adding ASIO_DECL in front of it, it resolves correctly and the scheduler and kqueue_reactor objects initialize properly avoiding the bad access to concurrency_hint().
In my case I am trying to use non-Boost ASIO inside of a VST3 audio plug-in running in Ableton Live 11 on macOS on an M1 processor. Using the VST3 plug-in in I'm getting this same crash. Using the same plug-in in other DAW applications, such as Reaper, does not cause the crash. It also does not occur for Ableton Live 11 on Windows.
I've got it narrowed down to the following issue:
In asio/detail/impl/service_registry.hpp the following method attempts to return a function pointer address to a create/factory method.
template <typename Service>
Service& service_registry::use_service(io_context& owner)
{
execution_context::service::key key;
init_key<Service>(key, 0);
factory_type factory = &service_registry::create<Service, io_context>;
return *static_cast<Service*>(do_use_service(key, factory, &owner));
}
Specifically, this line: factory_type factory = &service_registry::create<Service, io_context>;
When debugging in Xcode, in the hosts that work, when inspecting
factory, it shows the correct address linking to the service_registry::create<Service, io_context> static method.
However, in Ableton Live 11, it doesn't point to anything - somehow the address to the static method does not resolve correctly. This causes a cascade of issues, ultimately leading up to trying to invoke the factory function pointer in asio/asio/detail/impl/service_registry.ipp in the method service_registry::do_use_service. Since it doesn't point to a proper create method, nothing is created, it results in uninitialized objects, including the scheduler instance.
Therefore, when calling scheduler_.concurrency_hint() in kqueue_reactor.ipp the scheduler is uninitialized, and the EXC_BAD_ACCESS error results.
It's unclear to me why under some host processes, dynamically loading the plug-in cannot resolve the static method address, but others have no problem. In my case I compiled asio.hpp for standalone ASIO into the plug-in directly, there was no linking.
The best guesses I can come up with are
maybe your http_server might start additional threads or even fork. This might cause io_context and friends to be accessed after startLocalhost returned. To explain the crash location appearing to be at the indicated line, I could add the heuristic that something is already off during the destructor for ioc
the only other idea I have is that actually the opening/binding of the acceptor throws, but due to possible incompatibilities of types in the shared module vs the main program, the exception thrown is not actually caught and causes abnormal termination. This might happen more easily if the main program also uses Boost libraries, but a different copy (build/version) of them.
In this case there's a simple thing you can do: split up initialization and use the overloads that take error_code to instead use them.
I've written my own access layer to a game engine. There is a GameLoop which gets called every frame which lets me process my own code. I'm able to do specific things and to check if these things happened. In a very basic way it could look like this:
void cycle()
{
//set a specific value
Engine::setText("Hello World");
//read the value
std::string text = Engine::getText();
}
I want to test if my Engine-layer is working by writing automated tests. I have some experience in using the Boost Unittest Framework for simple comparison tests like this.
The problem is, that some things I want the engine to do are just processed after the call to cycle(). So calling Engine::getText() directly after Engine::setText(...) would return an empty string. If I would wait until the next call of cycle() the right value would be returned.
I now am wondering how I should write my tests if it is not possible to process them in the same cycle. Are there any best practices? Is it possible to use the "traditional testing" approach given by Boost Unittest Framework in such an environment? Are there perhaps other frameworks aimed at such a specialised case?
I'm using C++ for everything here, but I could imagine that there are answers unrelated to the programming language.
UPDATE:
It is not possible to access the Engine outside of cycle()
In your example above, std::string text = Engine::getText(); is the code you want to remember from one cycle but execute in the next. You can save it for later execution. For example - using C++11 you could use a lambda to wrap the test into a simple function specified inline.
There are two options with you:
If the library that you have can be used synchronously or using c++11 futures like facility (which can indicate the readyness of the result) then in your test case you can do something as below
void testcycle()
{
//set a specific value
Engine::setText("Hello World");
while (!Engine::isResultReady());
//read the value
assert(Engine::getText() == "WHATEVERVALUEYOUEXPECT");
}
If you dont have the above the best you can do have a timeout (this is not a good option though because you may have spurious failures):
void testcycle()
{
//set a specific value
Engine::setText("Hello World");
while (Engine::getText() != "WHATEVERVALUEYOUEXPECT") {
wait(1 millisec);
if (total_wait_time > 1 sec) // you can put whatever max time
assert(0);
}
}
I'm trying to create a test environment for using an external C++ API so that I can test things offline without having to be connected to the actual service. In essence, I want to create my own fake service that will be used for testing purposes. However, I want to be able to change between these two environments easily without having to change a ton of code. Basically, I want to be able to use the external C++ API classes in a test environment somehow. One problem I'm running into is that since the classes are part of an external API, I can't change them. I can only wrap them in other classes I create. How can I deal with that while being able to create an environment that doesn't require me changing a ton of code every time I want to switch back and forth? I have some sample code below (the relevant pieces where the API is being used). How can I put these classes below in a test harness? Thanks!
...
SessionOptions sessionOptions;
sessionOptions.setServerHost(d_host.c_str());
sessionOptions.setServerPort(d_port);
Session session(sessionOptions);
if (! session.start())
{
std::cerr <<"Failed to start session." << std::endl;
return;
}
if (! session.openService("//blp/mktdata"))
{
std::cerr <<"Failed to open //blp/mktdata" << std::endl;
return;
}
...
SubscriptionList subscriptions;
std::set<std::string>::const_iterator cItorSubscriptionStrings(m_SubscriptionStrings.begin());
for ( ; cItorSubscriptionStrings != m_SubscriptionStrings.end(); ++cItorSubscriptionStrings)
{
subscriptions.add((*cItorSubscriptionStrings).c_str(),
"LAST_PRICE,BID,ASK,TIME",
"",
CorrelationId((char*)(*cItorSubscriptionStrings).c_str()));
}
session.subscribe(subscriptions);
while (true)
{
Event event = session.nextEvent();
MessageIterator msgIter(event);
...
while (msgIter.next())
{
Message msg = msgIter.message();
if (event.eventType() == Event::SUBSCRIPTION_DATA)
{
if ((msg.hasElement("LAST_PRICE")) || ((msg.hasElement("BID")) && msg.hasElement("ASK")))
{
double mid = 0;
if ((msg.hasElement("BID")) && (msg.hasElement("ASK")))
{
mid = (msg.getElementAsFloat64("BID") + msg.getElementAsFloat64("ASK")) / 2;
}
else
{
mid = msg.getElementAsFloat64("LAST_PRICE");
}
...
}
}
}
...
}
One thing you can do is to use the interface (i.e. the header files) and provide an implementation of your own, at least for those functions you care about. To switch between both versions essentially amounts to linking with different libraries: yours for testing, theirs for the real implementation.
There are a few issues with that which can be addressed e.g. by only retaining the public interface and changing the private interface (on this case compilation needs to be directed at the different declarations, e.g. using different search pathes for the headers):
often the stubbed version wants to store different data
some object may need to construct private subobjects in specific ways
inline function may call other functions you don't really want to implement
You could try introducing a simplicator (http://www.natpryce.com/articles/000785.html). If the given API isn't amenable to testing, introduce a new thin interface on top of it that is.
I'm designing an interface that can be used to report errors in C++. (I'm working with a legacy system where exceptions are out of question.) In my youthful naivety, I started along these lines while designing my API:
bool DoStuff(int amount, string* error);
Return value signals success/failure, while error is used to report a human readable explanation. So far so good. Subroutine calls passed along the error pointer and everything was hunky-dory.
I ran into the following problems with this design (so far):
Cannot report warnings.
Not thread-safe.
Next, I decided to go with the following interface, instead of plain string:
class Issues {
public:
void Error(const string& message);
void Warning(const string& message);
void Merge(const Issues& issues);
}
So that I can change my API like this:
bool DoStuff(int amount, Issues* issues);
I'm wondering, is there a more generic/standard API out there that deals with this problem? If yes, I'd like to take a look.
UPDATE: I'm not looking for a logging library. For those who are curious, imagine you're writing a query engine that includes a compiler. The compiler issues warnings and errors, and those need to be returned to the user, as part of the response. Logging has its place in the design, but this is not it.
I usually use things like boost::signals or .NET delegates to report errors/warning/logging/whatever. You report errors with no changes to the interface, and the library user plugs whatever she wants to the signal to get the error reports (writing to a file, updating a console window, aborting the program, throwing an exception, ignoring warnings, etc).
Something like this, at eg. global scope:
boost::signal<void(std::string const&)> logError;
boost::signal<void(std::string const&)> logWarning;
and then
void routineWhichMayFail()
{
...
if (answer != 42)
{
logError("Universal error");
return;
}
}
and you connect something to logError and logWarning at initialization:
void robustErrorHandler(std::string const& msg)
{
std::cerr << "Error: " << msg << "\n";
std::exit(EXIT_FAILURE);
}
void initializeMyProgram()
{
logError.connect(&robustErrorHandler);
}
You can even throw exceptions in the error handler instead of exiting, and use fancier things than bare functions (logging classes, "delegates" -- pointers to methods with a this object bundled, RPC to a distant server). This way, you decouple the error handling from error reporting, which is good. You can also report to multiple destinations, you can even have your handlers return a boolean telling whether the action should be eg. retried.
From your explanation it sounds like you are trying to implement a logging library for your project. You can look at log4cpp or Boost.Log.