Deutsch   English   Français   Italiano  
<vakb55$2sp38$2@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!3.eu.feeder.erje.net!feeder.erje.net!news.mb-net.net!open-news-network.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: pozz <pozzugno@gmail.com>
Newsgroups: comp.arch.embedded
Subject: Unit Testing: from theory to real case
Date: Tue, 27 Aug 2024 12:52:21 +0200
Organization: A noiseless patient Spider
Lines: 141
Message-ID: <vakb55$2sp38$2@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Tue, 27 Aug 2024 12:52:21 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="1272178789861a50b38a3a8ee1dc912f";
	logging-data="3040360"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX191MAfZ7pBvqvfgfMquxTHGNcOjVqSeA/U="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:O1sxbWYjp8840SFxBMsxgyC4TDQ=
Content-Language: it
Bytes: 6628

I read a lot about unit testing, but unfortunately I usually work on 
single-developer projects with stressing time constraints, so I never 
created full tests for an entire project in the past. This means I'm a 
newbie in this aspect of software development.

I know the importance of testing, but we have to admit that it increases 
the cost of software development a lot, at least at the beginning. Not 
always we have the possibility to invest this price.

Everytime I start writing some tests, I eventually think I'm wasting my 
precious time. Most probably because I'm not able to create valid tests.

So I'm asking you to help on a real case.

First of all, I have a great confusion in my mind about the subtle 
differences about mocks, stubs, fakes, dummies and so on. Anyway I think 
these names are not so important, so go on.

These days I'm working on a calendar scheduler module. The client of 
this module can configure up to N events that could be:
- single (one shot)
- weekly (for example, on Monday and Saturday of every weeks)
- monthly (for example, the days 3-5-15 of every months)
- yearly (for example, the day 7 of months Jan, Feb and Mar)
Weekly, monthly and yearly events have a starting time and *could* have 
a maximum number of repetitions (or they could be forever).

The interface is very simple. I have some functions to initialize the 
configuration of an event (a simple C struct):

void calev_config_init_single(CalendarEventConfig *config, time_t 
timestamp, CalendarEventActions *actions);
void calev_config_init_weekly(CalendarEventConfig *config, time_t 
timestamp, uint8_t weekdays, unsigned int nrep, CalendarEventActions 
*actions);
void calev_config_init_monthly(CalendarEventConfig *config, time_t 
timestamp, uint32_t mdays, unsigned int nrep, CalendarEventActions 
*actions);
void calev_config_init_yearly(CalendarEventConfig *config, time_t 
timestamp, uint16_t months, unsigned int nrep, CalendarEventActions 
*actions);

I have a function that initializes the module with some pre-programmed 
events:

   void calendar_init(CalendarEventConfig *list_events, size_t num_events);

I have a function that is called every second that triggers actions on 
occurrences:

   void calendar_task(void);

So, the client of calendar module usually does the following:

   CalendarEventConfig events[4];
   calev_config_init_...(&events[0], ...
   calev_config_init_...(&events[1], ...
   calev_config_init_...(&events[2], ...
   calev_config_init_...(&events[3], ...
   calendar_init(events, 4);
   while(1) {
     calendar_task();  // every second
     ...
   }

The calendar module depends on some other modules. First of all, it asks 
for the current time as time_t. It calls make_actions() function, with 
certain parameters, when an event occurrence expired.

I know how to fake the time, replacing the system time with a fake time. 
And I know how to create a mock to check make_actions() calls and 
parameters.

Now the problem is... which tests to write?

I started writing some tests, but after completed 30 of them, I'm 
thinking my work is not valid.

I was tempted to write tests in this way:

TEST(TestCalendar, OneWeeklyEvent_InfiniteRepetition)
{
   CalendarEventConfig cfg;
   calev_config_init_weekly(&cfg, parse_time("01/01/2024 10:00:00"),
      MONDAY | SATURDAY, 0, &actions);

   set_time(parse_time("01/01/2024 00:00:00"));  // It's monday
   calendar_init(&cfg, 1);

   set_time(parse_time("01/01/2024 10:00:00"));  // First occurrence
   mock().expectOneCall("make_actions")...
   calendar_task();

   set_time(parse_time("06/01/2024 10:00:00"));  // It's saturday
   mock().expectOneCall("make_actions")...
   calendar_task();

   set_time(parse_time("08/01/2024 10:00:00"));  // It's monday again
   mock().expectOneCall("make_actions")...
   calendar_task();

   mock().checkExpectations();
}

However it seems there are many sub-tests inside 
OneWeeklyEvent_InfiniteRepetition test (the first occurrence, the second 
and third).
The tests should have a single assertion and should test a very specific 
behaviour. So I split this test in:

TEST(TestCalendar, OneWeeklyEventInfiniteRepetition_FirstOccurrence)
TEST(TestCalendar, OneWeeklyEventInfiniteRepetition_SecondOccurrence)
TEST(TestCalendar, OneWeeklyEventInfiniteRepetition_ThirsOccurrence)
What else? When to stop?

Now for the weekly event with only 5 repetitions.
TEST(TestCalendar, OneWeeklyEvent5Repetitions_FirstOccurrence)
TEST(TestCalendar, OneWeeklyEvent5Repetition_SecondOccurrence)
TEST(TestCalendar, OneWeeklyEvent5Repetition_SixthOccurrence_NoActions)

The combinations and possibilities are very high. calendar_init() can be 
called with only 1 event, with 2 events and so on. And the behaviour for 
these cases must be tested, because it should behaves well with 1 event, 
but not with 4 events.

The events can be passed to calendar_init() in a random (not 
cronologically) order. I should test this behaviour too.

There could be one-shot, weekly with infinite repetitions, weekly with a 
few repetitions, monthly... yearly, with certain days in common...

calendar_init() can be called when the current time is over the starting 
timestamp of all events. In some cases, there could be future 
occurrences yet (infinite repetitions) and in others that event can be 
completely expired (limited repetitions).

I'm confused. How to scientifically approach this testing problem? How 
to avoid the proliferation of tests? Which tests are really important 
and how to write them?