ThrowTheSwitch / CMock

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

How to get count for a mock method being invoked #428

Open pronoy13cap opened 1 year ago

pronoy13cap commented 1 year ago

I have a function which I want to mock and determine the number of times the function is invoked. is there any support available for this as the function is inside nested loop and it varies depending on conditions how many number of time the function is invoked. Example I have a chunk of code :- for (uint32_t Address = START_OF_MEMORY; Address < END_OF_MEMORY; Address += SINGLE_MEMORY_UNIT) { Retries = 0; while (TOTAL_RETRIES > Retries++) { if (FLAG_OK == MemoryErased(Address)) { break; } if(TOTAL_RETRIES <= Retries) { TotalFailures++; ResetSystem(); } } }

Here I want to mock "MemoryErased" and "ResetSystem" and get the count of how many times they get invoked.

Letme commented 1 year ago

When writing a test you know how many times it is going to be invoked before you changed the while loop condition (nice way to do it is to use function to get a flag, and mock its output). I do not know why you would have a use case where cmock would need to tell you how many times it would be invoked.

pronoy13cap commented 1 year ago

@Letme ,It is like in case of Google test framework, GMock, we have atleast/atmost to get to know that this function got invoked atleast 'n' number of times/atmost 'n' number of times it can be invoked. I want something similar.

Letme commented 1 year ago

So your feature request is to have ExpectAndReturnAtLeast(bla,return,10) which would generate 10 times ExpectAndReturn (instead of writing for loop for ExpectAndReturn call)?

At least or at most sounds like you dont know what you are doing. Mentality: "I assume this is going to be called 9 times, but I am happy if it is called 10 times" makes me wonder why you want to write a test in the first place, if you have no idea how many times you actually want to retry.

pronoy13cap commented 1 year ago

@Letme , I have a scenario, like where a function is invoked when I try to erase a sector of memory, let it be "fun()", I have a counter that keeps track of retries I want to do to erase the sector and say maximum times is "MAX", so , counter lies between 0 and MAX, so number times fun() is invoked will vary between 0 and counter, so how will I test it with cmock, as it will give "call more than expected number of times" or "called fewer times than expected"?

mvandervoord commented 1 year ago

To verify an indeterminate range at the moment, you can use the callback plugin to check whatever you want. The CMock 3 release will have support for ranges, but that's not going to be released for a bit yet.

Letme commented 1 year ago

@pronoy13cap That is easy - we all have to do with it. You need to mock hardware API. Retries are tracked with pulling of some hardware flag. Since you do not want to change that flag manually (could be it is even read-only in digital), you mock the function pulling that flag and then you can actually see what will happen if there is 0 retries (although it is unlikely), MAX retries, and TYPICAL number of retries. That means instead of relying hardware to actually return erase sector of memory (and to actually erase it) you mock your hardware and this even enables you to run the test much faster. And you can test what happens with max retries, without having to resort to some strange tricks in your test.

You want a repeatable-deterministic test case that is not reliant on external disturbances.

The range is what @mvandervoord says CMock will support (my above example), but we currently simply do that with a for loop (which takes a fair bit of RAM).

pronoy13cap commented 1 year ago

@mvandervoord thank you for the information, I hope Cmock 3 soon comes with the count feature, @Letme thanks for the support.

mvandervoord commented 1 year ago

Counting it already does. That was the first feature that CMock had. The change will be that instead of needing to specify an exact number you're expecting to happen, you will be able to specify a range.

In both cases, you need to tell CMock what is acceptable for your code, because that's it's job.

pronoy13cap commented 1 year ago

@mvandervoord , Counting how does it do, as far as I remember if "test()" is a function then "test_expect()", means expecting test function 1 time in the code execution. Now, for "test()" to be present in for loop , do I have to place then "test_expect()" also in for loop, or is there something like "test_expect(8)" where 8 is number of times I am expecting "test()" in the code execution?

Tuc-an commented 1 year ago

Yes, you can use a loop, or unroll the loop by repeating test_expect() 8 times. There is not a built-in shortcut for CMock to accomplish this.