ThrowTheSwitch / CMock

CMock - Mock/stub generator for C
http://throwtheswitch.org
MIT License
652 stars 269 forks source link

Mocking memcpy and ReturnThruPtr #244

Open IvanSlaev opened 4 years ago

IvanSlaev commented 4 years ago

I experienced the following problem unit testing embedded software written on C: When testing and want to mock memcpy all is perfect and works as expected until you decide to use ReturnThruPtr functionality. It seems that it is using memcpy internally. It leads to seg. fault when memcpy not expected and to non working ReturnThruPtr functionality when you e.g. memcpy_IgnoreAndReturn(); in the same test where ReturnThruPtr is used for another function!

mvandervoord commented 4 years ago

@IvanSlaev -- you are correct. Mocking memcpy is definitely a problem. I'm not sure it's one that is worth solving? (I'm open to other opinions).

To me, I'd never mock memcpy, because memcpy is basically taking the place of C's inability to use = to assign non-standard types. It's usually easy to verifying that the memcpy had the effect I wanted, without having to listen for the call itself.

Perhaps I am being naive with this? Thoughts?

In any case, one potential workaround for this issue:

In your software, you can use a macro instead, like so:

#ifndef TEST
#define MEMCPY(a,b,c) memcpy(a,b,c)
#else 
void* MEMCPY( void* destination, const void* source, size_t num );
#endif 

It's not ideal, but it would allow you to mock MEMCPY in tests and use it directly in your release code.

IvanSlaev commented 4 years ago

@mvandervoord -- thank you for the answer and for the workaround I am going to answer you sequentially: I personally think it is worth solving because it is a hidden problem, except you show it somehow - doc or ... . Otherwise it is coming from nowhere - you are happily trying to mock memcpy and then baam it strikes :). The unit test ideology is to mock everything so I do not agree of not mocking anything and maybe of restricted ability of mocking everything! I worked around this without polluting the code but I have to admit it is easier when you include source file. Source file including is a big mistake but the decision was not mine anyway I do not like polluting code with test stuff - debug stuff maybe, very rare, but test stuff - naah! That's my point of view!

P.S. I am not saying it is a big bug but it is, so maybe it can be low prioritized and fixed later, but I personally think it is worth! Anyway it is your decision!

mvandervoord commented 4 years ago

:) Thank you for the feedback. I really appreciate it.

I 100% agree with your viewpoint that it's a bug if it's something unexpected. We should not be in a situation where we have one-off problems that can't be handled (like using memcpy and then everything blows up. yikes!). If nothing else, it should fail gracefully. Better yet, it should work.

As an almost aside, I disagree with your statement that unit testing is about mocking everything else. I spend a lot of time teaching good unit testing practices and one of the things I teach is how to minimize the places where you are mocking. I love mocking. It's a super useful tool... but it's just one tool... and it has the downside of being closely tied to a particular implementation. So my (unsolicited, I realize) advice: keep using mocking where it's useful, but don't feel like it's a requirement for all problems.

:) anyway, Thanks again for the feedback. I'm going to leave this issue open so that I (or someone else) remember to come back to it and figure out a good solution.

IvanSlaev commented 4 years ago

@mvandervoord -- thank you for sharing your knowledge I will take your advice! Wish you all luck of having some spare time for fixing the issue!

wasder1234 commented 1 year ago

@mvandervoord -- thank you for sharing your knowledge I will take your advice! Wish you all luck of having some spare time for fixing the issue!

Ivan, can you please tell how you managed to get mock from memcpy function? I have troubles doing this. Generated .exe file crashes before main() somewhere in strerror_s() How at all it can be possible to mock such functions as memcpy and memset? I see in generated mock file (mock_xxx.c) generated mock code calls memcpy() and memset(). And in the same file we have mocks for this functions. Shouldn't linker throw "multiple declaration of 'memcpy'" msg? And if no, how linker knows it should link memcpy from string.h to Cmock generated code and mock of memcpy to my source code under test? Thank you