1.Ensure 100% test coverage
The tests planned should cover 100% of the software and hardware functionality that has been defined. No – actually it should cover 100% of what has been provided not just what has been planned. Something provided but not planned will end up being used in some way, and when this is not adequately tested, has often been the cause of failure in past high-reliability projects.
2.Consider coverage density
Quite obviously, spend more time/effort testing important and/or common items. For example single points of failure in hardware and software, or underlying system code. The temptation is to spend more time testing the easiest items to test.
3.Choose an appropriate set of test methods
There are, obviously, different types of test. The various forms of software test that I can think of are listed here. Different parts of a system with different characteristics and different levels of importance will attract different testing methodologies. This is a pragmatic and common-sense approach... just make sure that a note is kept of which method is used for which module, and why that method was chosen.
4.Designers have obligations and should be trusted
I constantly battle people who try to lead to 'documentation blowout'. This is the term I use when the documentation becomes so extensive, and has to cover so many small things that it ends up forming a large proportion of the available work effort.
The solution is two-fold. Firstly to be pragmatic in what is documented (get the most return for the investment) and secondly to trust the designer. Yes, the designer will make mistakes, and some of these may even slip through, but if you don't trust the designer, how can you agree with the design? Conversely, this places a large and weighty responsibility on the designer to not cut corners and to do the job right.
5.Plan the tests in advance, update the test plan later
The test plan should be written before the module under consideration is begun. Not the prototype stuff, but the actual end product design. The test plan tests against the functional requirements predominantly.
But, once the design is complete, the test plan should be revisited to add to and refine the tests in light of what you know about the design. I would be worried if that caused the test plan to be reduced in scope ... but it may be a good time to add tests that exercise a certain part of the design that the designer may feel is prone to being flaky.
6.Finding errors is a good thing
All humans make mistakes. The designer who finds faults with his system during the test phase has done a good job and should be praised. Imagine the consequence of that error NOT being found? Let me repeat this again: all designs have errors. It is good to find them.
7.Version control is your friend
Of course we know this is a good thing! But VC should be applied not only to software, but to the documents used to plan and design that software, to the test plan itself, the test vectors, the applied test, and to the test report and numerical test results. All of these version numbers should be recorded in the test result document.
If the version number of any of these parts changes from what was tested, the test MUST be repeated. Even seemingly simple changes can have unforeseen consequences. With embedded software, this is even more true.
8. Archive the test results
Any numerical results, or test vectors, even obvious ones, should be stored. It may only be necessary to do this for the latest version of test, but if in doubt, keep all.
You can refer to this data later. You may well need it and it could be the only proof you have that the design that you made actually works (and that it really is someone else's fault).
9.Do not be tempted to integrate before testing
This may be good fun in a prototype system, but is the kiss of death to a real production system. Think of it this way – your module contains a virus (an error/mistake). Any other module it touches can become infected with this. The module should remain in isolation until it has been cleared as virus free through testing.
With software this is obvious – copying and merging code is rarely as simple as copying a single function over. There may be globals, function prototypes, header files, constants and so on that need to change. The calling context may need to be changed. It is difficult to remember these changes and reverse them later if the copied code is removed or changed. Over time especially if this is done more than once, errors will creep in.
In hardware, overshoot or undershoot may cause device lifetime problems. In firmware, anyone who has programmed in VHDL knows the clutter that exists in the “Work” directory. Legacy functions can persist in there long after the source code has been removed from a design!
Unless the interface is very, very well defined and protected (for both software and hardware) it really is better to either avoid this temptation, or (in software), do it and then throw the code away afterwards... keep a very well defined roll-back point.
10.Testing is unglamorous
Yes, but so is being the one person who lets the team down.
You can not even guarantee good code by working hard alone, or even by being a 'good' programmer. Good programmers test their code properly, bad ones do not.
5 Principles of SOA
In many customer engagements, I need to establish a basic set of principles of SOA. The following sections introduce fundamental principles that a Service-oriented Architecture (SOA) should expose.These are not introduced as an absolute truth, but rather as a frame of reference for SOA-related discussions. You’ll note that the first four are based on Don Box’s four tenets, although over time they may have acquired a slight personal spin.
1. Explicit Boundaries
Everything needed by the service to provide its functionality should be passed to it when it is invoked. All access to the service should be via its publicly exposed interface; no hidden assumptions must be necessary to invoke the service. “Services are inextricably tied to messaging in that the only way into and out of a service are through messages”. A service invocation should – as a general pattern – not rely on a shared context; instead service invocations should be modeled as stateless. An interface exposed by a service is governed by a contract that describes its functional and non-functional capabilities and characteristics. The invocation of a service is an action that has a business effect, is possibly expensive in terms of resource consumption, and introduces a category of errors different than those of a local method invocation or remote procedure call. A service invocation is not a remote procedure call.2. Shared Contract and Schema, not Class
3. Policy-driven
To interact with a service, two orthogonal requirement sets have to be met:- the functionality, syntax and semantics of the provider must fit the consumer’s requirements,
- the technical capabilities and needs must match.
4. Autonomous
Related to the explicit boundaries principle, a service is autonomous in that its only relation to the outside world – at least from the SOA perspective – is through its interface. In particular, it must be possible to change a service’s runtime environment, e.g. from a lightweight prototype implementation to a full-blown, application server-based collection of collaborating components, without any effect on its consumers. Services can be changed and deployed, versioned and managed independently of each other. A service provider can not rely on the ability of its consumers to quickly adapt to a new version of the service; some of them might not even be able, or willing, to adapt to a new version of a service interface at all (especially if they are outside the service provider’s sphere of control).5. Wire formats, not Programming Language APIs
Services are exposed using a specific wire format that needs to be supported. This principle is strongly related to the first two principles, but introduces a new perspective: To ensure the utmost accessibility (and therefore, long-term usability), a service must be accessible from any platform that supports the exchange of messages adhering to the service interface as long as the interaction conforms to the policy defined for the service. For example, it is a useful test for conformance to this principle to consider whether it is possible to consume or provide a specific service from a mainstream dynamic programming language such as Perl, Python or Ruby. Even though none of these may currently play any role in the current technology landscape, this consideration can serve as a litmus test to assess whether the following criteria are met:- All message formats are described using an open standard, or a human readable description
- It is possible to create messages adhering to those schemas with reasonable effort without requiring a specific programmer’s library
- The semantics and syntax for additional information necessary for successful communication, such as headers for purposes such as security or reliability, follow a public specification or standard
- At least one of the transport (or transfer) protocols used to interact with the service is a (or is accessible via a) standard network protocol
Subscribe to:
Posts (Atom)