Академический Документы
Профессиональный Документы
Культура Документы
Objectives
for the 7-th Chapter
Who
who wrote it. This isn't actually true - the worst person is that programmer's mother,
because they never want to find fault with their son or daughter (but something
similar is with the programmer as well ! )
Why ? does
•the programmer knows how computers work, and thus wouldn’t try
something illogical or out of sequence.
Every programmer has had the experience of listening to a user describe
a set of steps they followed, and shaking their head, thinking, "Why in
the world would you do that?"
SE - Vasile Stoicu-Tivadar 3 / 36
Who does the testing ?
•the programmer’s natural mind-set is to make something work – not to try to break it.
And when it’s their own baby they’re testing, they’re definitely predisposed toward being
faint of heart when it comes to intentional demolition.
BUT despite their best intentions, the programmer has a vested interest (if only
subconsciously) in not finding any bugs in the application.
Regardless of which is true, it’s clear that someone other than the programmer should
test the application. Who?
SE - Vasile Stoicu-Tivadar 6 / 36
Who does the testing – continued 3
The advantages of having the users do the final
acceptance testing
There are variations to consider. Let’s look at the advantages of the customer becoming involved as
the primary testing resource at the end, based on the assumption that the customer should, and is
going to, provide daily and ongoing support for the application.
Why make that assumption? Just as a manufacturing company would hire a contractor to build
an addition, but use their own maintenance people for tasks like moving office partitions, a user
department would likely contract out for a large custom software development project. But they
wouldn’t want to rely on that staff for daily support of the application such as adding users,
changing vendor code numbers, or instructions on how to run the monthly posting transactions
in two parts. As a result, it’s important for the users to fully understand how to use the application
and what’s behind it. Then, when business conditions change, they can take full advantage of all
of the flexibility in the application, instead of having to assume nothing works the minute that the
environment changes.
-> via training, but it’s a long and expensive process, and is generally not very effective. Due to a
variety of constraints - such as scheduling people together at the same time - training on a large,
complex system is often done in a few full-day sessions. This is often not enough time to cover a
system thoroughly enough.
->The alternative, then, is to have the users who will be working with the system become
involved in the testing. By doing so, they’ll be able to spend more time with the system – perhaps by
spending a couple of hours a day over several weeks or months, instead of a week-long crash course.
Thus, they learn exactly what the system was intended to do, and they become expert in running the
system through all its paces.
Another advantage to the users doing the final testing is a lower cost. Meanwhile, their existing staff
is already paid for in the daily operations budget, so it "appears" to be free.
SE - Vasile Stoicu-Tivadar 7 / 36
Who does the testing – continued 4
Users have other jobs, and because of this, are prone to being less than
reliable in terms of getting the job done correctly and on time, if at all.
SE - Vasile Stoicu-Tivadar 8 / 36
Who does the testing – continued 5
WHAT is the solution ?
The optimal solution is a combination The best application of your limited resources - and
technical talent is just that - is toward the design and programming of systems. Bring in high
school and college students to do some of the functional testing, and then partner with the
appropriate customers who can and are willing to join in at the final stage to do the functional
testing.
And have someone on staff whose primary responsibility is testing. You could even think of
that person as being the QA department – for the most part, testing, but with other
responsibilities as well. These other responsibilities could involve the monitoring and handling of
your processes. Once your development staff stretches past a few people, the number of forms
and mechanisms to track grows. Verbal communication simply does not work. This QA person
makes sure that this process is running smoothly – in effect, performing QA on a macro scale as
well as with the details.
Including the customer in the functional testing doesn’t mean that the programming team
just disappears upon shipment of a late-beta CD. Their role during this phase of final testing
becomes that of "training mentor" and "technology transfer guide."
As training mentors, the programming team is still responsible for developing test plans
and instructing the customer’s testing staff on how to test properly.
In the technology transfer role, they’re responsible for training the testing staff as to the
functionality designed and implemented. As detailed as a functional specification is, it can
never cover every imaginable scenario. The programming team is also responsible for
training the customer’s staff about the internal technical details of the application.
SE - Vasile Stoicu-Tivadar 9 / 36
The process of testing
5 steps:
Unit testing - the functionality of an individual task or module is compared
against the specification
Integration testing - is defined as "do all the pieces work together" and the
level of detail and amount of effort will be proportional to "how many pieces" you've
got. Just as with Unit Testing, you have to have a definition of what the app is
supposed to do and how it's going to work. In this case - what are the pieces in the
game, and what are the rules and expectations of how the pieces are supposed to
interact?
12 / 36
The process of testing
Selection of test cases is difficult because full testing cannot be done
(all input combinations should be generated) and therefore a small set of test
stimuli must be chosen. There are two approaches:
- closed-box - the test system is viewed only from the perspective of inputs and
outputs
- open-box - the internal structure is also taken into account when testing
In a practical sense, steps one and two are usually performed together, but these make up two
separate columns in the checklist.
SE - Vasile Stoicu-Tivadar 14 / 36
The process of testing.
Unit testing-continued 1
Step three: test the rules
There are three general types of rules in an application - those attached to a field, those attached to
a form, and application-wide rules. In all three cases, these rules have to be identified and then
those rules have to be tested.
Identifying those rules is easy; they're in the functional specification! However, simply having a list
of rules isn't enough. The real work here falls on the shoulders of
the QA staff has to write up a detailed test plan that will verify those rules.
Once QA writes the test plan, they'll pass the test plan by the developer to make sure it's robust
and fairly covers the functionality. QA and the developer may work together to put together a case
chart to handle all of the possible options within a program and provide test data or require a test
plan to handle these cases. Finally, QA will execute it. As QA tests each option, they should be able
to check off which options were tested and what the result was.
SE - Vasile Stoicu-Tivadar 15 / 36
The process of testing.
Unit testing-continued 2
Step four: break it!
As developers, we know our application works. Right? We don’t need anybody to prove to us that it
works - we’ve run the application after writing the code and we’ve seen that it works. Of course,
we’ve only seen that it works one time - why would we waste our time trying it more than once?
Up to this point, QA has simply been verifying functionality - much like an inspector would verify that
all the items on the packing list are indeed in the box. But the ultimate mission of QA is not to prove
that the application will work - their mission is to break the application.
So the final step in the testing process is to repeat the first three steps, but this time, pulling out all
the stops to be devious, conniving, and downright evil in trying to find ways to break the application.
The greatest fear of a testing person is that there’s a bug in the system that they didn’t find.
SE - Vasile Stoicu-Tivadar 16 / 36
Testing Process
Integration testing
(see A4 , pag. 303 )
Does the app work in the production environment? I know of shops who
actually set up test environments that mimic the production environment of the
customer, and do a separate round of system testing in that environment. As
you can imagine, I think this is quite a luxury, both in terms of having the
resources to do so, and the time (and money) to do yet another round of
testing. After all, someone is paying for the testing, and, ultimately, it's the
customer.
However, no matter how much you try, it's going to be near on impossible to
precisely duplicate the customer's environment. As an example, witness the
fragility of Windows (before 2000) even after a decade of use all over the
world. Optimally, your application will have to have some bodacious exception
handling for unexpected environmental conditions and situations
SE - Vasile Stoicu-Tivadar 18 / 36
The process of testing.
Acceptance testing
This maps directly to the inspection department in a factory, where boxes from the
receiving dock are opened and the parts are examined to make sure they meet the
standards of the customer.
It's a rare customer who will actually perform full blown acceptance testing; even
rarer is the customer who, after doing a poor job of acceptance testing, will not
complain about finding defects in the application.
You can help this situation to an extent by providing test scripts - even your own test
plans, if you like - for your customer to use for their acceptance testing. If they feel
that a lot of their work has been done for them, they may be more inclined to pitch in
and do their part.
Be aware that if your user still doesn’t use the materials you’ve given them, you’ll
have to run through them yourselves – you’ll suffer in the end, regardless of "whose
fault" it was that testing wasn’t done.
If you don’t have a model office as described in the Integration Testing section,
another option you might consider for user acceptance testing is a test environment
at a customer’s site. You have to be careful to isolate it enough so it can’t impact
their actual production but not too much so you don’t get a reasonable test.
SE - Vasile Stoicu-Tivadar 19 / 36
The process of testing.
Regression testing
There are some automated test tools that perform some of the mundane
testing - and they can prove very handy precisely in this situation. However, as
we’ve already discussed, there are limits to these tools, and so the burden is
still on the QA department to ensure that nothing has been broken.
Doug Hennig uses a detailed change log that documents every change
made to an application in order to aid in hunting down the problems causes by
changes to code. While this doesn’t solve the problem up front, it makes a
great deal of difference in tracking the problem down and determining where
else the bug might manifest itself.
SE - Vasile Stoicu-Tivadar 20 / 36
TEST PLANNING (A4 pag. 313)
Each step of the testing process must be planned (as each
other engineering activity):
• Establishing test objectives
• Designing test cases
• Writing test cases
• Testing test cases
• Executing tests
• Evaluating test results
SE - Vasile Stoicu-Tivadar 21 / 36
Automated Testing (A4, page 315)
The testing team uses automated testing tools, as well, besides
manual testing and automated theorem provers and symbolic execution tools
(that include specialised equipment, and specific software):
• Code Analysis Tools (analyse the source code from the
consistency and correctness of the code and algorithms,
data, correct sequence etc.)
• Test Execution Tools
• Capture and Replay or capture and playback
(especially for User Interface Testing )
• Stubs (simplified modules, meant to replace the original
ones, used only in testing process), special drivers
• Complex Testing Environments
• Test Case Generators
SE - Vasile Stoicu-Tivadar 22 / 36
Regarding diminishing returns
in testing
Testing is the most difficult of activities, because you're never done.
Unlike a programmer, who can, at some point, identify when they have
finished writing code that fulfills all of the requirements spelled out in the
functional specification, a tester can never be sure that they have found all
of the defects. As a result, the testing process becomes an exercise in
dealing with diminishing returns: If you find 100 defects during the first week
of testing, 50 defects during the second week, 10 during the third week, and
then 2 during each of the next three weeks, how many more weeks do you
want to continue to test?
This is the designers call, and the decision has to do with the quality
requirements of the application. Quality is a relative term, depending on
the use of the application. A usual desktop application probably doesn't
have to be tested very thoroughly. On the other hand, an application that
tracks retrofit schedules of heart monitoring equipment needs to be
considerably better, since errors have a potentially more catastrophic effect
(safety-critical systems – many real-time systems).
SE - Vasile Stoicu-Tivadar 23 / 36
Fault “Seeding” (see A4 page 318)
Is quite impossible to measure the number of faults in a software.
There is a technique for a rough estimate of the number of faults still
unidentified, the Fault “seeding”
This technique involves the implantation (seeding) of a number of faults in the source code,
the testing being done with limited objectives (for example by the time limit or the number of
faults found) by the test team, and estimating the number of remaining faulyts in the total
faults detected, dividing them into those found from the implanted ones and those found from
the non-implanted ones, based on the simplifying hypothesis that non-seeded errors are in the
same ratio, whether seeded or not:
Thus, the estimated number of faults is determined by the rule of three :
Number of Detected Seeded Faults Number of Detected Non-Seeded Faults
____________________________ = _________________________________
Total Number of Seeded Faults Total Number of Non-Seeded Faults
The method is easy to apply (implantation, of course, must be done by someone outside of the
testing team) but involves an additional load on the workload of the test team, plus an estimate
based on empirical evidence (there is no guarantee that the result corresponds to truth - "we
just make an idea").
IP - Vasile Stoicu-Tivadar 24 / 36
Example
One seeded 8 errors, other, after testing, identified 12
errors, 3 of them being seeded ones.
Then
Number of Detected NSF = 12 – 3 =9
3/8=9/TNrNSF
IP - Vasile Stoicu-Tivadar 25 / 36
Confidence in the Software (see A4 page 320)
Where s – nr of identified seeded faults during tests (even we don’t identify all)
26 / 36
Criteria for Ending Testing (A4, pag. 322)
BASED ON
•obtaining a desired Confidence in the software
•determination of the number of states, paths or branches
still pending for testing
•Determination of fault-prone code based on previous
experience of testing similar modules
IP - Vasile Stoicu-Tivadar 27 / 36
Techniques to make testing easier
Two very frustrating situations that occur during the testing process:
testing something that just worked a minute ago but doesn’t any longer
having to restore the environment because the application blew up and took every special
setting and switch with it
The cardinal rule for original test data: make it clean, robust and keep it in a location
that can be accessed easily so that the test data directory can be replenished with this
clean data on demand.
SE - Vasile Stoicu-Tivadar 28 / 36
Techniques to make testing easier –
continued
Original environment
You also have to be able to restore the environment back to its original state.
For example, suppose your application always runs with the flag for
exact comparisons set OFF. However, during one specific point in a
routine, you need to have the flag set to ON, so at the beginning of the
routine, you do so. At the conclusion of the routine, you set the flag
back OFF. But, somewhere in the middle of that routine, the system
crashes. If you don’t reset the flag, and simply run the application again,
any comparison that was relying on the exact comparison to be off will
now fail - and possibly send you down a blind alley for hours until you
realize what happened.
Create a quick general-purpose tool that will automatically reset your
development environment back to where it came from so that you’re always
starting with the same baseline, just as you did with a clean set of test data.
SE - Vasile Stoicu-Tivadar 29 / 36
Testing techniques
Track users
Even if you are creating a single user system, include a routine that automatically tracks the
user who is on the system. Often times, there will be more than one person using the system,
and providing them each with their separate login allows you to determine who was using the
system when problems occurred.
Track activities
Create a function at the start of every routine that logs the name of the user and the date and
time that they called the routine. The table that this information is placed in is relatively small
compared to the rest of the application, and you can clean it out at any time.
Knowing who was in a routine (and when) provides valuable information when trying to track
down particularly thorny or infrequent bugs.
Track errors
You should keep a very detailed error log that captures everything you consider valuable.
For instance, you should capture the error message, the line of code that causes the
error, the call stack of programs that led to the error, any parameters that were passed,
the name of the user and the time stamp, and a host of environment information, including
files open, libraries loaded, all memory variables, the current state of the environment,
and so on.
Some developers grab a screen shot at the time an error occurs. They take a snap
shot of the screen at a particular instance and store it to a file, and so can see what the user is
seeing at the time of the error. The only difficulty is that these screen shots are pretty big.
SE - Vasile Stoicu-Tivadar 30 / 36
Testing techniques - continued
Audit trail
Track the user and the date/time that a record was last changed, and, if you have the space, log this same
information for when the record was added. Yes, this information takes another 30-40 bytes per record, but it is
invaluable to being able to save to do detective work on what is happening later on.
A more involved version of an audit trail feature tracks every change to any field. While this log can get awfully
large awfully quick, it can be useful to be able to turn this on and off on demand in order to isolate a specific
problem.
Debugging tools
If you haven’t already, set up a series of developer tools on a menu pad that is only available to the developer.
These tools should allow you to suspend program execution, or cancel the program outright so that you can halt
and investigate the environment at any time. Make sure all of your debugging facilities are available and ready to
be enabled whenever you need them.
SE - Vasile Stoicu-Tivadar 31 / 36
Object-oriented testing (only as
lecture, if one needs, not for
Exam)
The many books on OOP (C++ and JAVA) tend not to deal with
testing/debugging.
Features:
SE - Vasile Stoicu-Tivadar 33 / 36
Testing rudiments
Every class should have an associated test file. Tests should provide crisp/fail results
and document the underlying purpose.
Example:
cout << “Testing if name is properly set bu entity constructor “ << endl;
entity *e = new entity (“trial”);
If (strcmp(e->get_name(), “trial”)==0) {
cout <<“test satisfied”;}
else {
cout << “test not satisfied”;}
Such tests can be entered into a file whose name associates to the name of the class
under test (example: testentity.cpp)
Whenever entity.h or entity.cpp is modified, testentity.cpp is also modified, if
necessary, and recompiled and executed to make sure the new code has not been
inadvertently corrputed.
SE - Vasile Stoicu-Tivadar 34 / 36
Testing rudiments – continued 1
Tools can be developed to minimize the routine drudgery.
Example: a class test can be defined that supports testing C++ classes (for a
container class)
//within above series, focus on empty()
main() {
Test * ConTest = new Test; //make a new instance of Test for this class
ConTest->Is_Equal(“con1->empty ?”, con1->empty(), TRUE);
// output “test passed” if container is empty
ConTest->ShowInfo(“Container Tests”,'’container.h container.C”,
“container"); // otherwise “test NOT passed”
SE - Vasile Stoicu-Tivadar 35 / 36
Testing rudiments – continued 2
Test supports documenting tests and their purposes, comparing query outputs
with expected values, and automatically tallying test results.
Example: some output of the test; we can see at a glance at the end of the
printout that there were tests that failed and then by scanning the file we can
easily identify which ones they were.
Test Focus: contalner::empty()
In the early stages, however, a
---------------------
con1 empty?: True full printout is most likely not to
ShowInfo:
Test passed. be had:
----------------------
Title : Container Tests •many crashes occur that
Test Focus: container::size()
Test on File : container.h container.C halt the execution
con1’s size is 0? : True
Test Class : container
-----------------------
Test passed. •The run-time system may
give little or no indication of
Creating new entity book …
Test Focus: container::add(“entity ”) the cause of the crash
& container::is_in(“entity ")
Object entity exists.
book is added, and is in con 1? : False
In such cases, the point at
Test NOT passed
Creating new container con1 with no name … which printing stopped
…..
Object container exists. provides useful information
Report:
----------------------- since the point of failure must
-----------------------
contalner::add() & contajner::is_in() tests
series Total Series : 7
have occurred after it. In
----------------------- Total Test : 25
contrast, look-and-see testing
Error Detected :5 may result in a crash and offer
----------------------- no clue as to what caused it.
SE - Vasile Stoicu-Tivadar 36 / 36
Blueprint-based testing
Rudimentary test-supporting tools raise new questions:
•How do we determine what series of tests to run ?
•How do we come up with the purpose of each test and then implement it ?
•How many tests are enough ?
If both are based on the
Solution : the implementor supplies a class definition blueprint and are
the tester provides a test suite developed independently
and in parallel
A way for testing -> to list each query-terminated sequence of commands in a file and check
whether the actual response agrees with the value dictated by the behavior specification (like
in the example with the container).
BUT we don’t know about how to choose a sample (a finite set of pairs in the behavior
relation). There are two approaches: the first one focuses on the intended
functionality of the class -> SE - Vasile Stoicu-Tivadar 37 / 36
Constructing behavior samples
An object behavior specification (class alarm) :
constructor
alarm make-alarm(key)
commands open?(open(alarm)) = T
open?(close(alarm)) = F
alarm’ arm(alarm,key) //set the alarm to work using the proper key
sound?(arm(alarm,key))) = sound?(alarm)
alarm' disarm(alarm,key) //turn off the alarm using the proper key
key = key?(alarm)=>sound?(disarm(alarrn,key)) = F
alarm’ open(alarm) // open the door
sound?(disarm(alarm, key)) = sound?(alarm)
alarm’ close(alarm) // close the door
// only applies when above condition fails
armed?(alarm)=T => sound?(open(alarm)) = T
Equivalences sound?(Open(alarm))= sound?(alarm)
// only applies when above condition fails
open?(make-alarm(key)) =F
sound?(make-alarm(key)) =F
key?(make-alarm(key)) = key
SE - Vasile Stoicu-Tivadar 38 / 36
Constructing behavior samples – continued 1
Scenarios:
The main function of the alarm : to sound when it is armed and a break-in occurs.
Thus, if the alarm is armed with the right key and the door is subsequently opened, we want the alarm to sound.
=> The following query-terminated sequence and response
alarm = make-alarm(key1)
alarm' = arm(alarm,key1)
alarm" = open(alarm)
sound?(alarm")= T
Somebody knowing the right key should be able to get in by disarming the alarm:
alarm = make-alarm(key1)
alarm' = arm(alarm,key1)
alarm" = disarm(alarm,key1)
sound?(alarm") = F
But not knowing the proper key, a burglar will not be able to disarm the alarm and it will still warn of a break-in:
alarm = make-alarm(key1)
alarm' = arm(alarm,key1)
alarm" = disarm(alarm',key2)
alarm'" = open(alarm")
sound?(alarm'")=T
SE - Vasile Stoicu-Tivadar 39 / 36
Constructing behavior samples – continued 2
These query-terminated sequences represent normal user scenarios for the alarm, and its proper response is critical to its
existence. However, there are many other possible sequences that might arise in practice that must be tested.
Arming the alarm with the wrong key and subsequently opening the door; does the alarm sound?
alarm = make-alarm(keyl)
alarm' = arm(alarm,key2)
alarm" = open(alarm')
sound?(alarm") = ?
Arming the alarm with the right key,subsequently opening, then closing the door; can the alarm be armed?
alarm = make-alarm(key1)
alarm' = arm(alarm,key1)
alarm" = open(alarm')
alarm"' = close(alarm")
alarm iv= arm(alarm'",key1)
armed?(alarm iv ) = ?
SE - Vasile Stoicu-Tivadar 40 / 36
Constructing behavior samples – continued 3
Arming the alarm with the right key, subsequently opening the door, then forgetting to close the door: can the alarm be
armed?
alarm = make-alarm(key1)
alarm' = arm(alarm,key1)
alarm" = open(alarm')
alarm"' = arm(alarm",key1)
armed?(alarm''')= ?
Since the behavior specification is complete and consistent, each of the above responses can be worked out by
simulation. Clearly, we should test for them and as many other scenarios that might arise as possible.
But is there any way of knowing if all the scenarios have been considered ?
No, but our second approach can guarantee that all "aspects" of the behavior have been considered (query /
command pairs, or equivalently, state transitions).
SE - Vasile Stoicu-Tivadar 41 / 36
Testing constructors for correct initialization
Before proceeding with the query/command pairs, let's note that the query/constructor pairs in the
object behavior specification provide the information for defining constructors and testing that they work
properly. For example, the query/constructor pairs for class alarm are:
armed?(make-alarm(key)) = F
open?(make-alarm(key)) = F
sound?(make-alarm(key)) = F
key?(make-alarm(key)) = key
SE - Vasile Stoicu-Tivadar 42 / 36
A State transition –based testing
Objects are state machines (although no necessarily finite state machines). To fully test such a
system obviously requires that we test the transitions and outputs of the object in each of its states.
The state equations in an object behavior specification provide the information we need to do such
testing.
A complete specification contains all combinations of state representing queries and commands.
Example: the alarm class has three state-representing queries: armed?, open? and sounding?
Each returns a boolean value, so there are at most 23 = 8 states. Assuming the implementation
uses instance variables armed, open, and sounding, let's make eigh instances, each in a
different state:
SE - Vasile Stoicu-Tivadar 43 / 36
A State transition –based testing –
continued
We have to write 16 query/command pairs (see the behavior specification). Example for one equation:
armed ?(open(alarm))=F
can be transformed to the method:
alarm::armed_q_on_open(){
open();
return armed_q()==F;
}
test(alarm1->armed_q_on_open);
test(alarm2->armed_q_on_open);
…
test(alarm8->armed_q_on_open);
We have 16 query/command pairs for each of the 8 instances, so we will have 128 pass/fail tests.
SE - Vasile Stoicu-Tivadar 44 / 36
A State transition –based test
methodology
A framework for supporting
this methodology:
The main steps of the methodology:
1. Write test methods for each
query/command equation in the Test
object behavior description,
purpose
2. Form a container of these test
precondition
methods,
postcondition
3. Form a container of instance
makers in different states, virtual make_instances
4. Apply each test method to each test_instances
instance (freshly reconstituted as
test_results
necessary).
print
5. Form a container of test results
execute
showing the pairs of tests and
instances they failed on. apply_test
test_of_X
test1
…
testn
SE - Vasile Stoicu-Tivadar 45 / 36
A State transition –based test
methodology
Example
To test a class X, we define a subclass test_of_X:
Class test_of_alarm: public Test{};
The methods will implement the tests developed from the object behavior specification:
Bool test_of_X::query_on_command(X * testInstance){
............ //local constants to be used for arguments and tests
purpose = ............ ; //description of test objective
precondition = ........; // condition that must be satisfied by test instance
testInstance-> ........; // command sent to test instance
postcondition = ....... ; // condition that should be true after commands
}
SE - Vasile Stoicu-Tivadar 46 / 36
A State transition –based test
methodology
Example – continued
The precondition corresponds 1 of the rule, while the postcondition
to the "if" part
represents the "then" part.
A rule in the behavior specification has the form precondition => postcondition
though in many rules the precondition is only implicitly there. For example, the second rule:
armed?(arm(alarm,key)) = F
only applies when the previous rule does not. Thus, its explicit form is:
not(open?(alarm) = F & key?(alarm) = key) =>armed?(arm(a?arm,key)) = F
is translated as
Bool test_of_alarm::armed_q_on_open() {
purpose = 'test if alarm always is not armed after open”;
precondition = T;
test_instance->open();
postcondition = !test-instance->armed_q();
}
SE - Vasile Stoicu-Tivadar 48 / 36
A State transition –based test
methodology
Example – continued
Step 3 in the methodology 3 "instance makers
calls for providing that can be called
to generate fresh copies of instances”:
class test_of_alarm:public Test{
public:
test_of_alarm():Test(){}
void make_instances() {
test_instances = new set;
alarm * alarm 1 = new alarm (/* armed */F, /* open */F, /* sounding */F, /* key*/"key” );
test_instances->add(alarm1);
…
alarm * alarm8 = new alarm (/* armed */T, /" open */T, /*sounding*/T, /* key*/”key1”);
test_instances->add(alarm8);
}
For each test developed as above, we write a corresponding method for class test_of_alarm that uses a
macro to apply the test to each of the test instances. For example, for the test
test_of_alarm::armed_q_on_arm1
int main() {
test_of_alarm *t = new test_of_alarm();
t-> armed_q_on_arm1_all();
t-> armed_q_on_arm2_all();
t-> armed_q_on_open_all():
t-> armed_q_on_close_alI();
t->print();
}
The results appear in the form of an instance of test_result, which is an instance of class
function, holding for each failure-detecting method the container of failed instances.
For example, the print-out:
SE - Vasile Stoicu-Tivadar 51 / 36
A State transition –based test
methodology
Final considerations
In a relatively small finite state system such as alarms, it is feasible to completely cover the
state space with test instances. However, this may not be feasible for a large state space or if the state
space is infinite, as in the case of container classes.
The guiding principle must be to cover the tests rather than the states - use enough test
instances so that every' test is applicable at least once (within the limits of time and money,
the more test instances, the better)
Minimal test coverage : for each test, we make a test instance that will apply to that test.
But if we have the same test with different preconditions, we need to split this test in two different ones.
Example: a test that will apply to any instance with an open door but with different key settings (input
key is correct or incorrect).
SE - Vasile Stoicu-Tivadar 52 / 36
What this chapter means for You
You can use the concepts from this chapter in the following ways:
as individual
- to learn about the tests, especially about acceptance testing
- to guide your practical actions in object-oriented testing
as team
- the project manager can use the knowlidge about testing for an
appropriate approach in the management of the project and in the
relationship whith the customer
- allows to co-ordinate the activity of the design team and of the
testing team, especially for object-oriented testing
SE - Vasile Stoicu-Tivadar 53 / 36
Thank You for Your
attention !
SE - Vasile Stoicu-Tivadar