SCA/SCA Component/SCA Testing SCA Applications Principles
Testing unit and integration tests for an SCA application consists in testing component services, integration of components and external services, and composite services. In the following, we call "SCA element" a component or a composite.
Writing and performing unit and integration tests for SCA applications is very similar.
The only difference in the tooling job is the number of mocked up references. And for the user, what changes from one to the other is the interaction with the tooling (dialogs, right-clicks...) and the TestCases he has to write.
Writing tests for an SCA element consists in:
- Generating testing code to run these tests, distinct from the business code which should not be modified to run tests. This can be made by the tooling.
- Completing a JUnit TestCase skeleton with test methods. This has to be done by the user.
This is common to unit and integration tests. Only the number of mocked up references changes. In unit tests, all the references are mocked up. In integration tests, this number vary from 0 to n-1 references (where n is the number of references of the element).
Roughly, here are the usage steps:
- You have an SCA application in your work space (composite, interfaces, implementations).
- You ask to generate a testing project.
- for( every element to test )...
- You ask to generate a TestCase.
- The tooling generates a new SCA application (composite, interfaces, implementations) from the original SCA application. This means that several SCA applications co-exist in your workspace and share common elements. It sets coherence issues that are discussed farther.
- The user completes a JUnit TestCase by using EasyMock features to mock references.
- The user can run thse tests from Eclipse or keep them for later.
Generated testing applications have the following properties:
- They are SCA applications with Java implementations only.
- They are made up of two components: the first one's implementation contains the TestCase. The second one is related to the element to test. References of this second component are either wired to services of the first component (which will define references behavior during tests) or wired with the effective elements (real components or external services).
- In any case, they respect one of the two following patterns.
Testing a component
In this case, we copy-paste the component and its elements in the testing application.
Testing a composite
In this case, we generate a component with the same services and references than the composite, and having the composite as implementation (which means we copy the entire business application in the testing application). To avoid code duplication, we should allow the definition of dependencies between SCA projects, in the same way it is done with Java projects.
This implicitly means:
- One test => One SCA application. This is a strong constraint, but it allows you to separate your tests and to not modify your business application. Besides, this will let you the possibility to re-run these tests in a future iteration (non-regression tests).
- An excellent organization of the test project to keep it useable and manageable.
- Coherence constraints must be checked so that when the tested project evolves, the tester project evolves in consequence. As an example, if an implementation is changed, and that a test is using it, then this implementation should be reimported into the tester project (or its reference should be updated). This could be done using a builder.
Pros and Cons / Test Philosophy
- We do not touch the business code.
- Tests are saved from one iteration to another, so that we can run non-regression tests.
- Most of the testing code is generated, the tester can focus on writing TestCases.
- We can use JUnit and EasyMock even when the business implementation are not written in Java (the SCA platform deals with that for us).
- We do not simply test services. We tests services by defining references behavior. This requires the tester to know how references are used by the implementations and in which conditions. It means we can not have the same approach with SCA elements than with Java interfaces / classes (i.e. be able to write tests only from the interfaces). This might be solved by providing more flexibility in the use of EasyMock (e.g. let the implementation define the behavior of the mock at runtime, so that the user can avoid defining it himself). This is an issue if we want to do "Test Driven Development" with SCA projects.
Comments are welcome about this. :)