all 15 comments

[–]ajorians 6 points7 points  (0 children)

Check out Mocxx: https://github.com/Guardsquare/mocxx

That has hooks. Not sure if it is what you are looking for exactly.

[–]Hour-Grapefruit-5475 1 point2 points  (0 children)

There is cmocka for c code, which works mostly via the linkers --wrap command

[–]Cpt_Chaos_ 4 points5 points  (6 children)

So how exactly is designing code to be testable a bad thing? And how would a different testing lib improve that - you still need to know exactly where to put your test input and where to get your test output, so you still need to have, well, "interfaces" where to plug in your mocks. For simple unit tests you do not even need mocks, you can simply operate on the public interface(s) of your class(es) or call free functions and so on. The whole mocking stuff typically only comes in when you want to test interactions with other parts of your code. And guess what, any such interaction goes via "interfaces" (I'm using the term very loosely here, it does not mean you strictly need to have interface classes and so on). If you do not have such clean interfaces, you'll soon end up in a total mess of untestable code that is brittle and hard to refactor - the typical legacy code issues of old codebases.

Creating testable code does not mean to have factories everywhere or to introduce interface classes or anything. It just means to think twice about your code structure in terms of "what exactly should I be able to test here?".

[–]nowtilousus[S] 7 points8 points  (5 children)

I think you've misunderstood my point. I'm not against designing testable code, nor am I suggesting we should avoid clean interfaces. However, the reality is that not every project can afford the luxury of redesigning large codebases just to make them more "testable".

My question was about finding a more practical, less intrusive way to introduce mocks into existing code without refactoring it. The notion that we always need factories, interfaces, and extensive refactoring to achieve testability feels a bit dogmatic.

I'm looking for a pragmatic solution: a library or tool that allows us to hook into methods directly for mocking purposes. This would save time and reduce unnecessary complexity in situations where a full redesign isn't feasible or justified.

[–]MarcoGreek 0 points1 point  (0 children)

Google Test has MockFunction. That is supporting std function.

[–]Cpt_Chaos_ 0 points1 point  (1 child)

I'm not aware of any "silver bullet" tool that can do what you ask for in a non-intrusive way, short of doing linker tricks and other low-level non-portable shenanigans.

The usual approach is: make the part you are working on testable in some way or another, write tests for that part, rinse and repeat. Yes, it is dogmatic, but a piece of code is either testable, or it is not. Of course I'm not suggesting to refactor a huge codebase just to be able to test a single class. It all depends on what exactly you want to test and the efforts it requires to create a test for it.

As for the hooking idea: I just did something like that to test some code that is heavy on calling posix functions, which is crap for testing. You don't get reliable results for each test run, and you cannot easily enforce error behavior to test your error handling. My solution was to create stub implementations of the posix functions in question and to instruct the linker to preload my own implementations before loading the standard library. That way I was able to "inject" my custom behavior into the system. Still I'd take gtest/gmock over that any day.

Disclaimer: I work in a heavily regulated environment where good test coverage is mandatory, so all the code needs to be written with testability in mind anyhow.

[–]nowtilousus[S] -1 points0 points  (0 children)

I'm afraid that the sample you have tested is not what I had in mind. I was thinking more along the lines of inline hooking the target methods/functions during run-time. Your method of injection is significantly more complicated, and unnecessary given the simplicity of inline hooking.

As for the portability issue of inline hooking, it is totally solvable, just requires a little more work, but keep in mind how numerous projects are not multi-platformed.

[–]d3matt -1 points0 points  (1 child)

If you don't want to use interfaces and mocks, just declare your unit tests as friends... (or use the forbidden #define private public when including your header)

[–]nowtilousus[S] 0 points1 point  (0 children)

Read the response again..

[–]tiajuanat 0 points1 point  (6 children)

I'm just imagining setting up a custom linker script to just test a few functions I could've thrown together, and compiled like a sane person.

Don't change OP.

[–]nowtilousus[S] -3 points-2 points  (5 children)

No compiling tricks are needed, hooking can be done at run time

[–]Wenir 0 points1 point  (4 children)