Alire + AUnit + VSCode workflow

Hello!
I would like to ask for your help on how to use the “tests” project generated by Alire? Or how to use it RIGHT?
I am a beginner in Ada programming but I am already quite good at creating simpler programs. I would like to program according to TDD principles and I plan to use AUnit.
However, I don’t know how to start: on the one hand, I am overwhelmed by the huge amount of information in the Alire and AUnit documentation. On the other hand, I don’t know how to “marry” them? And how will all this work as a workspace in VSCode?

Any help, suggestions or guidance would be greatly appreciated!

I’m shamelessly plugging my own code here which all have unit tests included:

Similar to C# you create a separate test project. Unlike C# you place the test project in a sub-directory of your main project. The same applies if you want prove correctness with gnatprove.

As for Workspaces: I use two Workspaces - one for app/lib and one for test but with enough `.settings/´ magic you could probably just have one. I might try that. Would be interesting to see how it goes.

A side note. Ada principles are incompatible with the test driven design concept. Ada has in mind a careful upfront design of specifications followed by an implementation. Ideally tests must be written independently from the specifications by another team.

Thank you for the suggestions!

This may turn out to be a bit long, but I would like to explain the root cause of my original question, because it may make it easier to give me some guidance.

I think of myself as something of an “accidental” software developer, since I followed a fairly typical Eastern European path: as a child in the ’90s I started with BASIC and C64/MOS 6510 assembly, along with a bit of Z80, and later, in secondary school, I learned Turbo Pascal on the PC.

In higher education I studied Java and C, but by that time I already had some independent development tasks, which I implemented in C and C++.

In reality, I have never worked in a typical software development team. I have always been the software-development person in a team working on some kind of industrial control or measurement task. :slight_smile:

As a result, I was mostly spared the currently hyped, supposedly miraculous software development frameworks and methodologies — Scrum, TDD, Agile, and so on. Software has always been just one part of the overall development work, and that is still the case today.

When I need to write PC software, I currently work with C++17, Qt6 and related tools, using the OOP paradigm. I am comfortable in that environment, although I would not call myself a professional software developer.

My problem is mainly with embedded development. In that area, C has become something I would prefer to avoid in many cases, while modern C++ — although there is a lot to be said in its favor — often feels like a kind of forced fit.

I do understand that modern C++ has many advantages over C in embedded environments: zero-cost abstraction, RAII, constexpr, templates, and so on. But, for example, forcing OOP everywhere — especially inheritance — can often come at the expense of code readability.

My search for alternatives began when I started programming STM32 microcontrollers. The spaghetti code that ST produced with STM32Cube — an OOP-like HAL written in plain C — is simply dreadful.

I have tried Rust several times, and although I understand the intentions of the language designers and the advantages of the language, I still have not managed to like it. The hype surrounding the language, as well as the evangelizing tendency often seen among its enthusiasts, did not help either.

Of course, choosing a programming language should be an engineering decision based on objective criteria, which is why I keep giving Rust another try from time to time. But for me, its time has not yet come. :slight_smile:

Ada seems to be the ideal choice for about 80% of my tasks — the remaining 20% being plain C or assembly. Ada code is practically an engineering specification; it almost documents itself. So far, I have found almost everything in Ada that I used in C++, and in the vast majority of cases the Ada way seems more elegant and better from an engineering point of view.

Fortunately, I can use Ada not only in hobby projects. In my work, we have the possibility to implement certain less critical components — tooling, data conversion, and so on — using freely chosen tools.

At the moment, my only real problem is coordinating the development tools and working out a suitable development workflow.

I am not particularly attached to TDD; rather, I would like to understand what the modern “Ada way” is for proper software development.

I’m currently working on a simple audio DSP library, mainly for educational purposes. I want to test the modules of this library, which is where the idea of ​​using AUnit came from.
But I’m actually curious how you professional Ada programmers would do this?
If I’m going to learn a programming language/approach, I want to learn it WELL. (And not with bad habits…)

It massively depends on the project at hand. I prefer to design tests manually without any tools, because tools usually do not work well and tend to focus on irrelevant stuff.

For embedded software we invested a lot of work into the mocks and simulators. For example CAN bus message generators were written, ARM hosts were simulated etc. It is a lot of work just to list the risks in order of potential damage before even starting to think about designing a test for each scenario.

TDD makes it much more difficult because it is all upside down. If you think about it, it is basically a flow of failed integration tests from which you must work backwards to identify the problem and then to fix it. This is incredibly hard and the worst case scenario ever.

You should probably look at Ada SPARK because it saves a lot of testing. In general, test is the last resort when you cannot get it statically correct through typing and formal verification. But of course tests are essential nontheless.

I’m in a very similar position — most of my Ada work consists of single-person hobby projects too.

For me, Test-Driven Development works just as well in Ada as it does in other languages. It gives you a solid safety net, especially when you return to a project after a long break. I actually find the combination of TDD + Ada’s strong typing and Design-by-Contract features (runtime assertion checking) to be very productive.

I’m planning to write a practical tutorial covering:

  • Setting up AUnit tests with Alire
  • Using the SPARK prover (at least the lighter parts)
  • Modern project setup with Alire
  • VSCode workspace configuration (I still use GVim a lot too — VSCode has its quirks)

All of this will be part of my Pi-Ada-Tutorial.

From my work on the Raspberry Pi Pico, I can definitely say that Ada is a very clean and enjoyable way to do embedded programming — noticeably more pleasant than C. I’m confident it will work just as well for STM32 targets.

On-device unit testing is indeed more challenging (as it is on Android too), but it’s far from impossible. AUnit was designed with embedded/on-device testing in mind, so the foundation is there.

Feel free to ask any questions as you go — happy to help another hobbyist on the Ada journey! :rocket:

I’ll have to disagree here. I’ve been using Test-Driven Development successfully for about 20 years in Java, several years in C#, and more recently in Ada. It works just fine in Ada and is not particularly hard once you’re used to the workflow.

For me the biggest long-term win — especially on hobby projects — is the large suite of regression tests you build up almost for free. When you come back to a project after months or even years of inactivity, those tests give you real confidence that your bug fixes or changes haven’t broken anything else. That’s been invaluable for me.

Ada also gives you a nice extra: you can turn on contract checking (I use the validation profile in Alire) during unit testing, which adds dozens of extra assertions essentially for free.

I actually did try that route recently. I formally proved AdaCL_Embedded, and while it was a great learning experience, it was a lot of work for a one-man hobby project.

I’m a strong supporter of Design-by-Contract, but I won’t be attempting to prove Pico_Xbsp. For hobby-scale development the cost/benefit just doesn’t add up for me. TDD + contracts gives me enough confidence without crossing into full formal verification territory.

Are you sure it was TDD? Because TDD is not same as designing software testable, early testing, maintaining a test suite, requiring bug reports written as tests, designing tests upfront.

After all, it was Ada that introduced ACATS in parallel to designing first Ada compilers.

Otherwise I agree with all you wrote.

Writing the tests first works well in two cases. The first is if you fix a bug or change what the code does. You write a test which expects the new behavior, see the test fail, do the change, and see the test pass.

The other is if you know up-front how the interface is supposed to look like.

But often one still has to figure out the best interface, because it’s not obvious from the start. If you have already written a lot of tests, changing the interface breaks all your tests which makes the process painful.