Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.arch.embedded > #27752 > unrolled thread
| Started by | pozz <pozzugno@gmail.com> |
|---|---|
| First post | 2018-05-18 09:18 +0200 |
| Last post | 2018-05-19 08:15 -0700 |
| Articles | 5 — 5 participants |
Back to article view | Back to comp.arch.embedded
Unit testing for embedded development pozz <pozzugno@gmail.com> - 2018-05-18 09:18 +0200
Re: Unit testing for embedded development Tobias Baumann <tobias.baumann@elpra.de> - 2018-05-18 10:10 +0200
Re: Unit testing for embedded development Tom Gardner <spamjunk@blueyonder.co.uk> - 2018-05-18 09:17 +0100
Re: Unit testing for embedded development Paul Rubin <no.email@nospam.invalid> - 2018-05-18 01:23 -0700
Re: Unit testing for embedded development StateMachineCOM <statemachineguru@gmail.com> - 2018-05-19 08:15 -0700
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2018-05-18 09:18 +0200 |
| Subject | Unit testing for embedded development |
| Message-ID | <pdluoq$7rm$1@dont-email.me> |
I'm not an expert on test-driven development. I know the general ideas
behind TDD, however I never used it in my projects.
I want to start using TDD, at least creating some unit testing on some
more critical units. However I have many difficulties.
For a module that calculates a checksum, it is very simple to create a
unit test. However an embedded firmware is more complex.
Consider a simple example. When the user press button 1, a buzzer must
be activated for 1 second.
----- Start of buzzer.c -----
#include "timer.h"
#include "bsp.h"
statis Timer tmr_buzzer;
void buzzer_on(uint16 time_ms) {
TimerSet(&tmr_buzzer, time_ms);
bsp_buzzer_on();
}
void buzzer_off(void) {
bsp_buzzer_off();
}
void buzzer_task(void) {
if (TimerExpired(&tmr_buzzer)) {
buzzer_off();
}
}
----- End of buzzer.c -----
Of course I have a bsp.c/bsp.h and a timer.c/timer.h.
Now I want to create a unit test for buzzer module, to run on PC.
----- Start of test_buzzer.c -----
#include <stdbool.h>
#include "timer.h" /* driver for PC testing */
#include "bsp.h" /* bsp_buzzer_on/off declarations */
static bool buzzer_on;
int main(int argc, char *argv[]) {
/* Test if buzzer_on() works */
buzzer_on(10000);
if (!buzzer_on) ... test failed ...
/* Wait for 10010 ms */
if (buzzer_on) ... test failed ...
...
}
void bsp_buzzer_on(void) { buzzer_on = true; }
void bsp_buzzer_off(void) { buzzer_on = false; }
----- End of test_buzzer.c -----
How do you simulate passing of the time (wait for 1010ms)? Of course, I
don't want to wait 10 seconds for the test. I need to speed up the time.
Is this the correct way to create a unit testing for a buzzer library?
[toc] | [next] | [standalone]
| From | Tobias Baumann <tobias.baumann@elpra.de> |
|---|---|
| Date | 2018-05-18 10:10 +0200 |
| Message-ID | <pdm1pp$pde$1@dont-email.me> |
| In reply to | #27752 |
Am 18.05.2018 um 09:18 schrieb pozz: > > How do you simulate passing of the time (wait for 1010ms)? Of course, I > don't want to wait 10 seconds for the test. I need to speed up the time. > > Is this the correct way to create a unit testing for a buzzer library? You should think about placing constants like the buzzer on/off time in a header file and using preprocessor macros. Then you can use two different header files, one for unit testing and one for the real embedded system. -- Viele Grüße, Tobi https://www.elpra.de
[toc] | [prev] | [next] | [standalone]
| From | Tom Gardner <spamjunk@blueyonder.co.uk> |
|---|---|
| Date | 2018-05-18 09:17 +0100 |
| Message-ID | <K_vLC.327729$Cd3.117717@fx33.am4> |
| In reply to | #27752 |
You need to understand the concept of "mocking" w.r.t.
interfaces and time. Then you need to structure your
implementation so that the real interfaces can be replaced
with the mock interfaces during testing.
By symmetry, to unit test the interfaces you need to have
many mock applications.
On 18/05/18 08:18, pozz wrote:
> I'm not an expert on test-driven development. I know the general ideas behind
> TDD, however I never used it in my projects.
>
> I want to start using TDD, at least creating some unit testing on some more
> critical units. However I have many difficulties.
>
> For a module that calculates a checksum, it is very simple to create a unit
> test. However an embedded firmware is more complex.
>
> Consider a simple example. When the user press button 1, a buzzer must be
> activated for 1 second.
>
> ----- Start of buzzer.c -----
> #include "timer.h"
> #include "bsp.h"
>
> statis Timer tmr_buzzer;
>
> void buzzer_on(uint16 time_ms) {
> TimerSet(&tmr_buzzer, time_ms);
> bsp_buzzer_on();
> }
>
> void buzzer_off(void) {
> bsp_buzzer_off();
> }
>
> void buzzer_task(void) {
> if (TimerExpired(&tmr_buzzer)) {
> buzzer_off();
> }
> }
> ----- End of buzzer.c -----
>
> Of course I have a bsp.c/bsp.h and a timer.c/timer.h.
>
> Now I want to create a unit test for buzzer module, to run on PC.
>
> ----- Start of test_buzzer.c -----
> #include <stdbool.h>
> #include "timer.h" /* driver for PC testing */
> #include "bsp.h" /* bsp_buzzer_on/off declarations */
>
> static bool buzzer_on;
>
> int main(int argc, char *argv[]) {
> /* Test if buzzer_on() works */
> buzzer_on(10000);
> if (!buzzer_on) ... test failed ...
> /* Wait for 10010 ms */
> if (buzzer_on) ... test failed ...
>
> ...
> }
>
> void bsp_buzzer_on(void) { buzzer_on = true; }
> void bsp_buzzer_off(void) { buzzer_on = false; }
>
> ----- End of test_buzzer.c -----
>
>
> How do you simulate passing of the time (wait for 1010ms)? Of course, I don't
> want to wait 10 seconds for the test. I need to speed up the time.
>
> Is this the correct way to create a unit testing for a buzzer library?
[toc] | [prev] | [next] | [standalone]
| From | Paul Rubin <no.email@nospam.invalid> |
|---|---|
| Date | 2018-05-18 01:23 -0700 |
| Message-ID | <87zi0x9xtj.fsf@nightsong.com> |
| In reply to | #27752 |
pozz <pozzugno@gmail.com> writes:
> Is this the correct way to create a unit testing for a buzzer library?
A good way to do this type of thing with "dependency injection" and
"mock objects". It's traditionally done with OOP but you can do it with
plain C as well. You interface the external world through an object so
you'd say (pseudocode):
class World { ... };
class Real_world extends World { ... };
int run(World world) {
world.buzzer_on();
world.sleep(1000); // ms
world.buzzer_off()
}
int main() {
World w = new Real_world();
run(w);
}
or things like that. In the real system "world"'s methods would call
stuff from the BSP.
You'd also have a test class, e.g.
class Test_world extends World { ... };
int run_test() {
World w = new Test_world();
run(w); // run your application with the test world instead of
// the real one
}
The test world wouldn't trigger the real hardware, but instead would
just feed the application some canned fake data, and keep a few
variables to track whether the buzzer was on, how much time had passed,
etc. Then your unit tests would make sure those variables got updated
to the right values.
If you do this thoroughly enough, and have enough logging in your app
code, then when something goes wrong you can translate the logged input
stream into mock inputs in your test world. Then you can reproduce the
error by running the app with the test world instead of the real one, so
you don't have to go mess with all the buzzers and timers and stuff.
Once you've reproduced it, you can debug it completely in the test world
and with luck, the fixed version will work the real world.
Better yet, you can run and debug the test world completely on your
workstation with its capacious memory and nice debugging tools, without
touching the embedded hardware at all, no cross compiling, etc.
https://en.wikipedia.org/wiki/Mock_object might be sort of helpful.
[toc] | [prev] | [next] | [standalone]
| From | StateMachineCOM <statemachineguru@gmail.com> |
|---|---|
| Date | 2018-05-19 08:15 -0700 |
| Message-ID | <346316d7-8a73-4bea-82d2-af3828f413ff@googlegroups.com> |
| In reply to | #27752 |
Read the book "Test Driven Development for Embedded C" by James Grenning: https://www.amazon.com/Driven-Development-Embedded-Pragmatic-Programmers/dp/193435662X James has a whole chapter on faking the time.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.arch.embedded
csiph-web