By Smitheo
Jan 07 2025
Focusing on behavior-driven testing ensures your software meets requirements while saving time and effort. This approach eliminates unnecessary complexity, reduces maintenance overhead, and creates more reliable outcomes. Discover how shifting from implementation-based tests to behavior-driven testing can streamline workflows and improve product quality.
The last couple of years we spent a lot of time with writing and also practicing how to write good unit/integration tests in AEM (Adobe Experience Manager). Now I would like to share with you what I have learned so far. What I have learned is not only AEM related, you can apply it to any programming language or framework.
Before that time I had some "experience" with unit testing. I wrote several unit tests so that I can say "I have experience with it". But to be honest I didn't like to write it.
Even though I knew what benefits tests bring to the product that we are building, what brings to the team members and to me, I didn't care. Typical excuses were:
and in the end, nobody pushed me to write it. Sadly, writing tests wasn't part of the development process.
Now when I'm thinking a little bit, I don't know how to write tests. Let's face it, writing tests is not easy, like many other things when you don't have experience with it.
Luckily that kind of thing has changed at some point, and I would like to try to convince all of you who are still thinking like "old" me.
I would like that we all to start thinking more about Quality and not Quantity.
Most of us work in an "Agile" way (whatever that means) and use DDD (Deadline-driven development) methodology (I could write about that in a separate post). This usually means that there is no time for writing tests. This needs to be changed, developers and all other technical team members should convince all other team members that writing tests should be part of the development process. Writing tests should be part of any estimation. Period.
Why?
There are a lot of benefits, but I will point out the most important of them:
Now let's see typical "disadvantages":
Probably you have noticed that I have mentioned time and money as advantages and disadvantagess. Depending on if you are thinking in the short term, then yes it's a waist of time and money, but If you think in the long term then it's not true. Actually in the end it saves your time and money.
A lot of people think that they are a waste of time and money. I think because they don't see some visual outcome of them, like how they see it when you build some feature. Try to think like this, with tests you can prevent a lot of bugs and a lot of ping pongs between Developers and QAs. Very often we have change requests during development and it happens that we implemented something in the wrong way. The new request just doesn't fit anymore to the existing implementation. That means we need to refactor our old code or reimplement it from scratch. Here tests provides you a safe feeling because you know if you broke behavior or not. Another example could be big, never-ending projects where several different teams have worked before you. Probably that project has poorly written documentation, you need to deal with legacy code and implement new features on top of it. Having tests is gold here. Also, a lot of projects starts like MVP which turns out to some core/base projects with several subprojects. Not having test coverage here is total nonsense.
The last 3 disadvantages are also not true.
You don't believe me? Take 1 hour of your time and watch the talk "TDD, Where Did It All Go Wrong" by Ian Cooper. For me, this was an eye opener. Before this talk, I read a few books about testing and I was not so convinced. In my opinion, this is definitely the best talk about it.
TL; DR; of the talk:
This testing approach helps you to build the right product. But the negative point could be that it doesn't help you to build the product right. Another downside is that you don't see exactly what is wrong when the test is failing.
So classic unit testing approach pushes you to write more clean and quality code than "behavior testing". In my opinion, strict code reviews and static code analysis tools are better approaches to achieving the same result. The second downside for me is a really minor thing, since with debugging you can quickly find out what is happening.
I hope that you are still follow me and that I'm start changing a little bit your thinking about testing.
Now let's stop with theory and let's see how it works in practice.
Because last few years I have been working with AEM, I will show you how to test behaviors in your AEM projects. The same things you can apply in any other programming language or framework. Depending on testing library support, this can be easier or harder to achieve.
As an example let's say we need to implement Product Details API which is consumed by the client side. To build Product Details API let's say in Spring you will probably create several classes like Product Controller, Service, Repository, DTO, and so on. In the AEM world, this means you need to create Sling Servlet, OSGi Service, Sling Model, and some DTO classes.
Product Details acceptance criteria:
Implementation what you will see here is not perfect, it's simplified and hardcoded. In the real world, this is more complex. But here implementation is not important, instead, we should focus on how to test the requirements of this API.
I will add here just 3 most important classes, other implementations you can see on Github
Except for those 3 classes, I need to create several more:
You saw that we have a lot of classes to build this user story. Usually, what developers test here are OSGi services. I'm not saying this is a bad approach, but for that, you will need more time, and every time when you refactor your code or add some new stuff, it's very likely that you will need to change your tests as well.
Instead of that let's test only Servlet because this is the public API of this user story. So what do we need to test in Servlet? First of all, we need to cover all requirements from acceptance criteria, additionally, we can cover some technical details of servlet implementation.
At the moment in my opinion the best library that you can use is AEM Mocks. AEM Mocks supports the most common mock implementations of AEM APIs + contains Apache Sling and OSGi mock implementations. For other not-implemented mocks, you will need to implement it by yourself or use Mockito. Besides those two I will use Junit 5.
Some tips before we start:
You will see that this test class is more or less clean and it focuses only on tests. There is no mocking here, separated mock example you can see here. I'm using @BeforeAll and @BeforeEach to do some common setups, like setting up market pages/resources and common request information. Also, I needed some helper classes to easier register all necessary classes into AEM context. All resources are exported as JSON from real AEM instances and imported into the AEM context so that we test on real data.
In this test class, I'm testing technical details and requirements
With this testing approach, I have covered 87% of lines of code. The other 13% that is not covered is catching exceptions.
import Image from 'next/image'
Other good examples for testing in AEM would be components. For every component you have requirements. To achieve those requirements you will probably create several classes like OSGi service, some Utils, and Records, and those requirements you will publicly expose through the Sling model to the view layer. Ideal candidates for testing.
Leverage best practices and tailored solutions to drive success. Contact us today to learn how we can help optimize your Adobe Experience Manager implementation.