A deployment diagram/model is an undirected graph showing nodes, components, and connections.
A node represents a physical computational resource. UML uses cube-shaped icons to represent nodes.
There are two node stereotypes: <<processor>> and <<device>>. A processor has processing and storage capabilities, such as a computer or a database manager. A device may have storage capabilities, but not processing capabilities. Printers, terminals, and disk drives are examples of devices.
Nodes may have attributes such as name, capacity, speed, and reliability. The name of a node may include its type:
big-blue:
MainFrame
An association between two nodes represents a physical connection. Connections can be stereotyped by communication protocols:
<<TCP/IP>>,
<<UDP/IP>>, <<X.25>>, <<Frame Relay>>,
<<ATM>>
<<HTTP>>, <<FTP>>, <<Telnet>>,
<<Email>>
<<RS-232>>, <<modem>>
<<PSTN>>, <<ISDN>>
<<Ethernet>>, <<Token Ring>>, <<Token Bus>>
<<ODBC>>, <<RMI>>, <<RPC>>,
<<COM>>, <<CORBA>>
Objects and components may reside on or are assigned to a node.
In UML, a component is, "a physical, replaceable, part of a system that realizes one or more interfaces." A component icon is a rectangle with tabs. An interface is a labeled circle.
This definition is pretty good. I would simplify it further by simply defining a component to be any object that is known to its clients through one or more interfaces that it implements. "Replaceable" and "physical" more or less follow as consequences. When most people think of components, they think of Java Beans and/or COM objects such as Active X controls. Both of these are covered under both definitions. Of course one might well ask why we can't simply use object diagrams to represent components.
Another issue is what is meant by the term "interface". The Java definition of interface as a collection of function signatures is clearly not complete enough to allow us to develop replaceable objects. In fact, the definition of interface used when talking about Java Beans is extended to include how properties are accessed and changed. COM interfaces include meta interfaces that allow clients to query a component about its properties, the events it fires, and the services it provides.
UML claims its definition of component should also include files (executable and data), libraries (dynamically and statically linked), documents, and tables. (These are all component stereotypes). I find this extension a bit confusing.
From Rose:
Done using the Word diagram editor:
Here's a Rose model that shows testing concepts.
There are (at least) three dimensions to testing:
In theory, we can devise tests that combine any three of these dimensions.
Component Level
Test design and implementation of a function or class. Also called unit testing. Programmers should create a test harness as a static member function for every class they create:
Integration Level
Test design and implementation of collaborations and subsystems.
System Level
Internal test of the function of the entire system. (alpha testing)
Acceptance Level
Stakeholder test of the function of the entire system. (beta testing) All tests should be test cases associated with use cases specified at the beginning of the development process.
Structural analysis verifies the system's design. Functional analysis validates the system's behavior.
Dynamic testing involves executing the program. Static testing involves
inspecting the code. Code reviews (walkthroughs and inspections) and
correctness proofs are well known examples of static testing.
1. Decide who will do the testing. This should be a creative programmer different from the code developer.
2. Decide when testing will end.
3. Select what is to be measured. What will the goal of the test be?
4. Decide how the test will be conducted.
5. Develop the test cases. Test cases should be associated to use cases.
6. Execute the test cases using a test harness.
7. Carefully compare the results with the test oracle.
black-box testing
Same as functional analysis.
boundary testing
Testing the system using inputs at or beyond their expected ranges.
error
A programmer mistake.
failure
Incorrect behavior resulting from a bug.
fault
Bug.
glass-box testing
Same as structural analysis.
quality assurance
regression testing
Re-testing components and collaborations after changes have been made to the system.
stress testing
Testing a system under extreme work loads.
verification
Are we building the product correctly?
validation
Are we building the correct product?
white-box testing
Same as structural analysis.
References
Chapter 12 of Software Engineering: An Engineering Approach, by Peters & Pedrycz; Wiley, 2000.
Chapter 5 of Classical and Object-Oriented Software Engineering ed. 4, by Schach; McGraw Hill, 1998.
#include <iostream>
#include <iomanip>
#include <cassert>
using namespace std;
#define
DEBUG_MODE
// #undef DEBUG_MODE
class Account
{
public:
Account(double amt = 0)
{
#ifdef DEBUG_MODE
cout << "entering Account(), amt = " << amt <<
endl;
#endif
assert(0 <= amt);
balance = amt;
#ifdef DEBUG_MODE
cout << "exiting Account()\n";
#endif
}
virtual ~Account()
{
#ifdef DEBUG_MODE
cout << "entering ~Account()\n";
#endif
#ifdef DEBUG_MODE
cout << "exiting ~Account()\n";
#endif
}
void withdraw(double amt)
{
#ifdef DEBUG_MODE
cout << "entering withdraw(), amt = " << amt <<
endl;
#endif
assert(0 <= amt);
if (amt <= balance)
balance -= amt;
else
cerr << "Sorry, insufficient funds\n";
#ifdef DEBUG_MODE
cout << "exiting withdraw()\n";
#endif
}
void deposit(double amt)
{
#ifdef DEBUG_MODE
cout << "entering deposit(), amt = " << amt <<
endl;
#endif
assert(0 <= amt);
balance += amt;
#ifdef DEBUG_MODE
cout << "exiting deposit()\n";
#endif
}
double getBalance() const { return balance; }
//
unit test harness
static void
test(ostream& log = cout);
private:
double balance;
};
ostream& operator<<(ostream& os, const Account& acct);
#include "account.h"
ostream& operator<<(ostream& os, const Account&
acct)
{
os.setf(ios::fixed, ios::floatfield);
os << setprecision(2); // try a manipulator
os << "balance = $" << acct.getBalance()
<< endl;
os.precision(6);
os.setf(0, ios::floatfield); // reset
return os;
}
void Account::test(ostream& log)
{
log << "\nentering Account::test() ... \n";
Account* a = new Account(20);
a->deposit(50);
log << *a;
a->withdraw(30);
log << *a;
a->withdraw(100);
log << *a;
a->deposit(-50);
log << *a;
log << "exiting Account::test() ... \n";
};
#include "account.h"
int main()
{
Account::test();
return 0;
}