Closed illegal-instruction-co closed 8 months ago
Unit tests WIP right now I think they will be enough, no need for the rest. The unit tests kind of will have integration tests anyways, can't really separate because unit testing some methods require other methods to succeed.
Unit tests WIP right now I think they will be enough, no need for the rest. The unit tests kind of will have integration tests anyways, can't really separate because unit testing some methods require other methods to succeed.
Integration tests are also needed. To cover all the code, at least 1 or 2 integration test should be enought.
I can't unit test without doing integration anyways. Example:
char *test_LM_GetThreadProcess()
{
lm_thread_t curthread;
lm_process_t curprocess;
lm_process_t process;
mu_assert("failed to get current thread", LM_GetThread(&curthread) == LM_TRUE);
mu_assert("retrieved invalid thread", CHECK_THREAD(&curthread));
mu_assert("failed to get current process", LM_GetProcess(&curprocess) == LM_TRUE);
mu_assert("retrieved current process is invalid", CHECK_PROCESS(&curprocess));
mu_assert("failed to get thread process", LM_GetThreadProcess(&curthread, &process) == LM_TRUE);
mu_assert("retrieved process is invalid", CHECK_PROCESS(&process));
mu_assert("processes don't match", EQUAL_PROCESSES(&curprocess, &process));
mu_assert("function attempted to run with bad arguments (invalid thread)", LM_GetThreadProcess(LM_NULLPTR, &process) == LM_FALSE);
mu_assert("function attempted to run with bad arguments (invalid proc)", LM_GetThreadProcess(&curthread, LM_NULLPTR) == LM_FALSE);
return NULL;
}
In this case, I'm unit testing the function LM_GetThreadProcess
. But to test it, I have to get some stuff to check against, in this case I need to get a process and a thread. So in this unit test, I'm testing LM_GetThreadProcess
while also requiring LM_GetProcess
and LM_GetThread
to work. Both of them are also tested before this function is tested.
Thats why we need to use dependency injection. If we are writing unit test, target fn must undepended.
Thats why we need to use dependency injection. If we are writing unit test, target fn must undepended.
Hmm... I never wrote deep tests before TBH. What do you think of the current state of the tests: https://github.com/rdbo/libmem/tree/master/tests/unit
Any advices? Better to get things done right early on then have to change everything later.
Ok, I'm doing proper dependency injection now - I'm storing the values after a successful test, and they are retrieved from the functions that need it.
I can make proper example tonight with pr. And another advice, i dont know how you think about using external libraries but googletest is best in this case.
I can make proper example tonight with pr. And another advice, i dont know how you think about using external libraries but googletest is best in this case.
I'm using minunit
because it's really small. In general I try avoiding using separate libraries, but if it's necessary, then why not.
I can't unit test without doing integration anyways. Example:
char *test_LM_GetThreadProcess() { lm_thread_t curthread; lm_process_t curprocess; lm_process_t process; mu_assert("failed to get current thread", LM_GetThread(&curthread) == LM_TRUE); mu_assert("retrieved invalid thread", CHECK_THREAD(&curthread)); mu_assert("failed to get current process", LM_GetProcess(&curprocess) == LM_TRUE); mu_assert("retrieved current process is invalid", CHECK_PROCESS(&curprocess)); mu_assert("failed to get thread process", LM_GetThreadProcess(&curthread, &process) == LM_TRUE); mu_assert("retrieved process is invalid", CHECK_PROCESS(&process)); mu_assert("processes don't match", EQUAL_PROCESSES(&curprocess, &process)); mu_assert("function attempted to run with bad arguments (invalid thread)", LM_GetThreadProcess(LM_NULLPTR, &process) == LM_FALSE); mu_assert("function attempted to run with bad arguments (invalid proc)", LM_GetThreadProcess(&curthread, LM_NULLPTR) == LM_FALSE); return NULL; }
In this case, I'm unit testing the function
LM_GetThreadProcess
. But to test it, I have to get some stuff to check against, in this case I need to get a process and a thread. So in this unit test, I'm testingLM_GetThreadProcess
while also requiringLM_GetProcess
andLM_GetThread
to work. Both of them are also tested before this function is tested.
I'm wondering how could this be done using GTest and Dependency Injection... My DI method is very basic, I just make a global variable that is assigned on a previous test, then used by whatever needs it.
First of all needed seperated test cases for each target fn.
#include <gtest/gtest.h>
extern "C" {
#include "your_code.h" // your C code header file
}
// Define your CHECK_THREAD, CHECK_PROCESS, and EQUAL_PROCESSES macros or functions here
class LMThreadTest : public ::testing::Test {
protected:
void SetUp() override {
// Setup code, if needed, for LM_GetThread tests
}
void TearDown() override {
// Tear-down code, if needed, for LM_GetThread tests
}
};
class LMProcessTest : public ::testing::Test {
protected:
void SetUp() override {
// Setup code, if needed, for LM_GetProcess tests
}
void TearDown() override {
// Tear-down code, if needed, for LM_GetProcess tests
}
};
class LMThreadProcessTest : public ::testing::Test {
protected:
void SetUp() override {
// Setup code, if needed, for LM_GetThreadProcess tests
}
void TearDown() override {
// Tear-down code, if needed, for LM_GetThreadProcess tests
}
};
TEST_F(LMThreadTest, GetCurrentThread) {
lm_thread_t curthread;
ASSERT_EQ(LM_GetThread(&curthread), LM_TRUE);
ASSERT_TRUE(CHECK_THREAD(&curthread));
}
TEST_F(LMProcessTest, GetCurrentProcess) {
lm_process_t curprocess;
ASSERT_EQ(LM_GetProcess(&curprocess), LM_TRUE);
ASSERT_TRUE(CHECK_PROCESS(&curprocess));
}
TEST_F(LMThreadProcessTest, GetThreadProcess) {
lm_thread_t curthread;
lm_process_t curprocess;
ASSERT_EQ(LM_GetThread(&curthread), LM_TRUE);
ASSERT_TRUE(CHECK_THREAD(&curthread));
ASSERT_EQ(LM_GetProcess(&curprocess), LM_TRUE);
ASSERT_TRUE(CHECK_PROCESS(&curprocess));
lm_process_t process;
ASSERT_EQ(LM_GetThreadProcess(&curthread, &process), LM_TRUE);
ASSERT_TRUE(CHECK_PROCESS(&process));
ASSERT_TRUE(EQUAL_PROCESSES(&curprocess, &process));
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
and link fake dependencies into test object instead of original ones. For example, your LM_GetThreadProcess depended to LM_ATHING method. Create a static library for LM_ATHING with std::function callbacks.
struct yourfakecallback final {
static inline std::function<void(int> LM_ATHING;
};
#include "yourfakecallback.h"
void LM_ATHING(int thing) {
return yourfakecallback::LM_ATHING(thing);
}
in your test case
TEST_F(LMThreadProcessTest, GetThreadProcess) {
yourfakecallback::LM_ATHING = [](int thing) {
thing = 5;
};
lm_thread_t curthread;
lm_process_t curprocess;
ASSERT_EQ(LM_GetThread(&curthread), LM_TRUE);
ASSERT_TRUE(CHECK_THREAD(&curthread));
ASSERT_EQ(LM_GetProcess(&curprocess), LM_TRUE);
ASSERT_TRUE(CHECK_PROCESS(&curprocess));
lm_process_t process;
ASSERT_EQ(LM_GetThreadProcess(&curthread, &process), LM_TRUE);
ASSERT_TRUE(CHECK_PROCESS(&process));
ASSERT_TRUE(EQUAL_PROCESSES(&curprocess, &process));
}
For now, I think tests are good enough. They are covering most of libmem's C library functionality and they have passed on Linux and Windows. I will close this for now.
Tests must be classificated as these 2 ( 3 ) parts: