Professional Documents
Culture Documents
Testing of S/W Project
Testing of S/W Project
REPORT TITLE
REMARKS
Submitted By Supervised By
Objectives
• Understanding and developing a comprehensive testing strategy such as white-box test-
ing.
• Utilizing basis path testing to construct a flow graph representing the software’s control
structure.
• Calculate the cyclomatic complexity of the implemented code to assess its structural
complexity.
• Systematically identify and document errors and bugs through the testing process to pro-
vide customizable user preferences.
• Prepare test cases that will force execution of each path in the basis set.
1
Flow Graph
The flow graph depicts logical control flow using the notation illustrated in figure 1. Each
structured construct has a corresponding flow graph symbol. A sequence of process boxes and
a decision diamond can map into a single node. The arrows on the flow graph, called edges or
links, represent flow of control and are analogous to flowchart arrows. An edge must terminate
at a node, even if the node does not represent any procedural statements
Cyclomatic Complexity
Cyclomatic complexity is a software metric that provides a quantitative measure of the logical
complexity of a program. When used in the context of the basis path testing method, the value
computed for cyclomatic complexity defines the number of independent paths in the basis set of
a program. It provides an upper bound for the number of tests that must be conducted to ensure
that all statements have been executed at least once. Cyclomatic complexity has a foundation
in graph theory and provides an extremely useful software metric. Complexity is computed in
one of three ways:
1. The number of regions of the flow graph corresponds to the cyclomatic complexity.
V (G) = E − N + 2
where E is the number of flow graph edges and N is the number of flow graph nodes.
V (G) = P + 1
Independent Path
An independent path is any path through the program that introduces at least one new set of
processing statements or a new condition. When stated in terms of a flow graph, an independent
path must move along at least one edge that has not been traversed before the path is defined.
By incorporating independent paths, software developers can design systems that respond flex-
ibly to different scenarios, allowing for conditional branching and alternative processing. The
visual representation of these independent paths in a control flow diagram assists developers in
understanding and designing the logic of their programs effectively.
2
Testing Strategy
There are multiple code segments that are crucial for our implementation of the project from
which five of them are specified here to be evaluated.
Here, there are two regions, 4 nodes, 4 edges and the number of predicate node is one. There-
fore, the cyclomatic complexity is:
V (G)1 = 2
V (G)1 = E − N + 2 = 4 − 4 + 2 = 2
V (G)1 = P + 1 = 1 + 1 = 2
3
Figure 2: Flow graph for code segment 2
Here, there are two regions, 3 nodes, 3 edges and the number of predicate node is one. There-
fore, the cyclomatic complexity is:
V (G)2 = 2
V (G)2 = E − N + 2 = 3 − 3 + 2 = 2
V (G)2 = P + 1 = 1 + 1 = 2
V (G)3 = E − N + 2 = 10 − 8 + 2 = 4
V (G)3 = P + 1 = 3 + 1 = 4
4
Figure 3: Flow graph for code segment 3
5
Figure 4: Flow graph for code segment 4
V (G)4 = E − N + 2 = 21 − 15 + 2 = 8
V (G)4 = P + 1 = 7 + 1 = 8
6
Path 4: 1 - 2 - 3 - 4 - 5 - 6 - 8 - 10 - 12 - 13 - 15
Path 5: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 10 - 12 - 13 - 15
Path 6: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 12 - 13 - 15
Path 7: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 15
Path 8: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 14 - 15
Here, there are 4 regions, 9 nodes, 11 edges and the number of predicate node is 3. Therefore,
the cyclomatic complexity is:
V (G)5 = 4
V (G)5 = E − N + 2 = 11 − 9 + 2 = 4
V (G)5 = P + 1 = 3 + 1 = 4
7
Path 3: 1 - 2 - 5 - 6 - 7 - 9
Path 4: 1 - 2 - 5 - 6 - 8 - 9
Development Tools
There are various tools we are expecting to use in this project. Such as–
• Flutter
• Firebase
Conclusion
In brief, software testing combines smart problem-solving with well-planned testing tech-
niques. The main goal is to make a set of tests that catch as many mistakes as possible. White-
box testing looks at how the program works on the inside, covering all the instructions and
conditions.
Using flow graph, a unique test can be produced on a project that can allow detecting almost
all errors. Testing is always ongoing, and when we design good tests, software developers can
fix mistakes before users find them. This ensures software is good quality, reliable, and works
well.
Appendix
Code Snippets
Below are the code snippets that were used to analyze flow graph and calculate cyclomatic
complexity.
enum A l l e r g y R e s p o n s e { yes , no }
8
enum N u t r i t i o n F a c t R e s p o n s e { yes , no }
RxInt c u r r e n t P a g e = 0 . obs ;
Rx<D i e t T y p e > d i e t T y p e = D i e t T y p e . h a l a l H a r a m . o b s ;
Rx<A l l e r g y R e s p o n s e > h a s A l l e r g i e s = A l l e r g y R e s p o n s e . no . o b s ;
Rx<A l l e r g e n > a l l e r g e n = A l l e r g e n . none . o b s ;
Rx<N u t r i t i o n F a c t R e s p o n s e > w a n t s N u t r i t i o n F a c t s =
N u t r i t i o n F a c t R e s p o n s e . yes . obs ;
int userIdCounter = 0;
v o i d s e l e c t D i e t T y p e ( D i e t T y p e v a l u e ) => d i e t T y p e . v a l u e
= value ;
v o i d s e l e c t H a s A l l e r g i e s ( A l l e r g y R e s p o n s e v a l u e ) =>
= value ;
void s e l e c t W a n t s N u t r i t i o n F a c t s ( N u t r i t i o n F a c t R e s p o n s e
v a l u e ) => w a n t s N u t r i t i o n F a c t s . v a l u e = v a l u e ;
void nextPage ( ) {
i f ( currentPage . value < 3) {
c u r r e n t P a g e . v a l u e ++;
}
}
Map<S t r i n g , dynamic> g e t U s e r D a t a ( ) {
return {
’ dietType ’ : dietType . value . toString ( ) . s p l i t ( ’ . ’ ) . last ,
’ hasAllergies ’ : hasAllergies . value . toString
9
( ) . split ( ’ . ’ ). last ,
’ allergen ’ : allergen . value . toString ( ) . s p l i t ( ’ . ’ ) . last ,
’ wantsNutritionFacts ’ : wantsNutritionFacts .
void f i n i s h Q u e s t i o n n a i r e ( ) {
f i n a l userData = getUserData ( ) ;
final userId = generateUserId ( ) ; / / Call a
f u n c t i o n t o g e n e r a t e t h e u s e r ID
F i r e s t o r e S e r v i c e ( ) . saveUserData ( userId , userData ) ;
Get . t o ( S i g n u p P a g e ( u s e r I d : u s e r I d ) ) ;
}
String generateUserId () {
u s e r I d C o u n t e r ++; / / I n c r e m e n t t h e c o u n t e r f o r
e a c h new u s e r
return ’ u s e r $ u s e r I d C o u n t e r ’ ;
}
}
var i s P a s s w o r d V i s i b l e = f a l s e . obs ;
void t o g g l e P a s s w o r d V i s i b i l i t y ( ) {
isPasswordVisible . value = ! isPasswordVisible . value ;
10
}
void r e g i s t e r U s e r ( S t r i n g email , S t r i n g password ){
String ? error = AuthenticationRepository .
as S t r i n g ? ;
i f ( e r r o r != n u l l ){
Get . s h o w S n a c k b a r ( G e t S n a c k B a r ( m e s s a g e : e r r o r . t o S t r i n g ( ) , ) ) ;
}
}
F u t u r e <void > c r e a t e U s e r ( UserModal u s e r ) a s y n c {
await UserRepository ( ) . createUser ( user ) ;
p h o n e A u t h e n t i c a t i o n ( u s e r . mobileNo ) ;
Get . t o ( ( ) => c o n s t OTPScreen ( ) ) ;
}
v o i d p h o n e A u t h e n t i c a t i o n ( S t r i n g mobileNo ) {
AuthenticationRepository . instance . phoneAuthentication
( mobileNo ) ;
}
}
i n s t a n c e . verifyOTP ( otp ) ;
i s V e r i f i e d ? Get . o f f ( c o n s t Home ( ) ) : Get . b a c k ( ) ;
}
}
11
GetxController {
s t a t i c A u t h e n t i c a t i o n R e p o s i t o r y g e t i n s t a n c e => Get . f i n d ( ) ;
@override
v o i d onReady ( ) {
Future . delayed ( const Duration ( seconds : 5 ) ) ;
f i r e b a s e U s e r = Rx<U s e r ? >( a u t h . c u r r e n t U s e r ) ;
f i r e b a s e U s e r . bindStream ( auth . userChanges ( ) ) ;
ever ( firebaseUser , setIntialScreen );
}
s e t I n t i a l S c r e e n ( User ? u s e r ) {
u s e r == n u l l ? Get . o f f A l l ( ( ) => c o n s t Welcome ( ) ) : Get
. o f f A l l ( ( ) => c o n s t Home ( ) ) ;
}
Try a g a i n ’ ) ;
}
},
codeSent : ( v e r i f i c a t i o n I d , resendTOken ) {
this . v e r i f i c a t i o n I d . value = v e r i f i c a t i o n I d ;
12
},
codeAutoRetrievalTimeout : ( v e r i f i c a t i o n I d ) {
this . v e r i f i c a t i o n I d . value = v e r i f i c a t i o n I d ;
});
}
F u t u r e <bool > v e r i f y O T P ( S t r i n g o t p ) a s y n c {
var c r e d e n t i a l s = await auth . signInWithCredential (
PhoneAuthProvider . c r e d e n t i a l (
v e r i f i c a t i o n I d : v e r i f i c a t i o n I d . value ,
smsCode : o t p ) ) ;
return c r e d e n t i a l s . u s e r != n u l l ? true : f a l s e ;
}
F u t u r e <void > c r e a t e U s e r W i t h E m a i l A n d P a s s w o r d ( S t r i n g e m a i l ,
S t r i n g password ) async {
try {
await auth . createUserWithEmailAndPassword (
email : email , password : password ) ;
f i r e b a s e U s e r . v a l u e ! = n u l l ? Get . o f f A l l ( ( ) =>
c o n s t Home ( ) ) : Get
. t o ( ( ) => c o n s t Welcome ( ) ) ;
} on F i r e b a s e A u t h E x c e p t i o n c a t c h ( e ) {
f i n a l ex = S i g n U p W i t h E m a i l A n d P a s s w o r d F a i l u r e . c o d e
( e . code ) ;
d e b u g P r i n t ( ’FIREBASE AUTH EXCEPTION − $ { ex . m e s s a g e } ’ ) ;
throw ex ;
}
catch ( ) {
c o n s t ex = S i g n U p W i t h E m a i l A n d P a s s w o r d F a i l u r e ( ) ;
d e b u g P r i n t ( ’EXCEPTION − ${ ex . m e s s a g e } ’ ) ;
throw ex ;
}
}
F u t u r e <void > l o g i n W i t h E m a i l A n d P a s s w o r d ( S t r i n g e m a i l ,
13
S t r i n g password ) async {
try {
f i n a l c r e d e n t i a l = await FirebaseAuth . instance
. signInWithEmailAndPassword (
email : email ,
password : password
);
Get . t o ( ( ) =>c o n s t Home ( ) ) ;
} on F i r e b a s e A u t h E x c e p t i o n c a t c h ( e ) {
i f ( e . c o d e == ’ u s e r − n o t − f o u n d ’ ) {
Get . s n a c k b a r ( ” E r r o r ” , ’No u s e r f o u n d f o r t h a t e m a i l . ’ ,
s n a c k P o s i t i o n : S n a c k P o s i t i o n .BOTTOM,
backgroundColor : Colors . redAccent . withOpacity
(0.1) ,
colorText : Colors . red ) ;
} e l s e i f ( e . c o d e == ’ wrong − p a s s w o r d ’ ) {
Get . s n a c k b a r ( ” E r r o r ” , ’ Wrong p a s s w o r d p r o v i d e d f o r
t h a t u s e r . ’ , s n a c k P o s i t i o n : S n a c k P o s i t i o n .BOTTOM,
backgroundColor : Colors . redAccent . withOpacity
(0.1) ,
colorText : Colors . red ) ;
}
}
c o n s t S i g n U p W i t h E m a i l A n d P a s s w o r d F a i l u r e ( [ t h i s . m e s s a g e = ”An
Unknown e r r o r o c c u r e d . ” ] ) ;
14
f a c t o r y SignUpWithEmailAndPasswordFailure . code ( S t r i n g code ){
switch ( code ){
c a s e ’ weak − p a s s w o r d ’ :
return const SignUpWithEmailAndPasswordFailure ( ’ Please
enter a
s t r o g e r password ’ ) ;
case ’ invalid −email ’ :
return const SignUpWithEmailAndPasswordFailure ( ’ Email
i s not
v a l i d or badly formatted . ’ ) ;
case ’ email − a l r e a d y −in −use ’ :
return const
S i g n U p W i t h E m a i l A n d P a s s w o r d F a i l u r e ( ’An a c c o u n t
t h i s email . ’ ) ;
case ’ o p e r a t i o n −not − allowed ’ :
return const
SignUpWithEmailAndPasswordFailure ( ’ Operation i s
not allowed .
15