Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

CHITTAGONG UNIVERSITY OF

ENGINEERING & TECHNOLOGY


DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

REPORT TITLE

Testing of the Project on E-code Analyzer

COURSE CODE : CSE 356


COURSE NAME : SOFTWARE ENGINEERING (SESSIONAL)
EXPERIMENT NO : 05
DATE OF SUBMISSION : 23 – 01 – 2024

REMARKS

Submitted By Supervised By

MD AKIB HASAN 1904015 Annesha Das


Assistant Professor
K.M. MAHABUB HOSSAIN 1904017
Department of CSE, CUET
SADMAN RAHMAN ANANTA 1904020
Sabiha Anan
Assistant Professor
Department of CSE, CUET
Introduction
In the dynamic landscape of software development, testing possesses a substantial share of
technical efficiency. Whether developing conventional or object-oriented software, a strate-
gic approach to test planning starts in small, focused on individual software elements before
expanding to the entire program.
The ultimate goal of software testing is error detection before delivering to the stakeholders,
achieved through systematic test steps such as unit and integration tests to validation and sys-
tem testing. Each step employs precise techniques, gradually broadening the abstraction level.
Basic path testing, equivalence partitioning, boundary value testing, black box testing etc. are
considered to ensure software evaluation.

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.

Basic Path Testing


Basis path testing is a white-box testing technique. The basis path method enables the test-case
designer to derive a logical complexity measure of a procedural design and use this measure as
a guide for defining a basis set of execution paths. Test cases derived to exercise the basis set
are guaranteed to execute every statement in the program at least one time during testing. The
steps of deriving the test set are:

• Using the design or code as a foundation, draw a corresponding flow graph.

• Determine the cyclomatic complexity of the resultant flow graph.

• Determine a basis set of linearly independent paths.

• 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.

2. Cyclomatic complexity V(G) for a flow graph G is defined as

V (G) = E − N + 2

where E is the number of flow graph edges and N is the number of flow graph nodes.

3. Cyclomatic complexity V(G) for a flow graph G is also defined as

V (G) = P + 1

where P is the number of predicate nodes contained in the flow graph G.

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.

Basic Path Testing – 1


Following graph shows the logical control flow using flow graph notation.

Figure 1: Flow graph for code segment 1

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

Hence, there will be two unique independent path:


Path 1: 1 - 2 - 4
Path 2: 1 - 2 - 3 - 4

Basic Path Testing – 2


Following graph shows the logical control flow using flow graph notation.

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

Hence, there will be two unique independent path:


Path 1: 1 - 3
Path 2: 1 - 2 - 3

Basic Path Testing – 3


Following graph shows the logical control flow using flow graph notation. Here, there are four
regions, 8 nodes, 10 edges and the number of predicate node is three. Therefore, the cyclomatic
complexity is:
V (G)3 = 4

V (G)3 = E − N + 2 = 10 − 8 + 2 = 4

V (G)3 = P + 1 = 3 + 1 = 4

Hence, there will be four unique independent path:


Path 1: 1 - 2 - 4 - 6 - 8
Path 2: 1 - 2 - 3 - 4 - 6 - 8
Path 2: 1 - 2 - 3 - 4 - 5 - 6 - 8
Path 2: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8

4
Figure 3: Flow graph for code segment 3

5
Figure 4: Flow graph for code segment 4

Basic Path Testing – 4


Following graph shows the logical control flow using flow graph notation. Here, there are 8
regions, 15 nodes, 21 edges and the number of predicate node is 7. Therefore, the cyclomatic
complexity is:
V (G)4 = 8

V (G)4 = E − N + 2 = 21 − 15 + 2 = 8

V (G)4 = P + 1 = 7 + 1 = 8

Hence, there will be eight unique independent path:


Path 1: 1 - 2 - 5 - 7 - 8 - 10 - 12 - 13 - 15
Path 2: 1 - 2 - 3 - 5 - 7 - 8 - 10 - 12 - 13 - 15
Path 3: 1 - 2 - 3 - 4 - 5 - 7 - 8 - 10 - 12 - 13 - 15

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

Basic Path Testing – 5


Following graph shows the logical control flow using flow graph notation.

Figure 5: Flow graph for code segment 5

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

Hence, there will be four unique independent path:


Path 1: 1 - 2 - 3 - 6 - 7 - 9
Path 2: 1 - 2 - 4 - 6 - 7 - 9

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

• Flutter gallery, Canva, draw-io

• Google play etc.

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.

Listing 1: Code Segemnt 1


enum D i e t T y p e { h a l a l H a r a m , vegan , v e g e t a r i a n }

enum A l l e r g y R e s p o n s e { yes , no }

enum A l l e r g e n { g l u t e n , d a i r y , n u t s , soy , none }

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 }

class QuestionController extends GetxController {


s t a t i c Q u e s t i o n C o n t r o l l e r g e t i n s t a n c e => Get . f i n d ( ) ;

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 ) =>

hasAllergies . value = value ;


v o i d s e l e c t A l l e r g e n ( A l l e r g e n v a l u e ) => a l l e r g e n . 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 .

value . toString ( ) . s p l i t ( ’ . ’ ) . last ,


};
}

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 ’ ;
}
}

Listing 2: Code Segemnt 2


class SignupController extends GetxController {
s t a t i c S i g n u p C o n t r o l l e r g e t i n s t a n c e => Get . f i n d ( ) ;
f i n a l email = T e x t E d i t i n g C o n t r o l l e r ( ) ;
f i n a l password = T e x t E d i t i n g C o n t r o l l e r ( ) ;
f i n a l userName = T e x t E d i t i n g C o n t r o l l e r ( ) ;
f i n a l mobileNo = T e x t E d i t i n g C o n t r o l l e r ( ) ;

GlobalKey <F o r m S t a t e > f o r m k e y = GlobalKey <F o r m S t a t e > ( ) ;

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 .

i n s t a n c e . createUserWithEmailAndPassword ( email , password )

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 ) ;
}
}

Listing 3: Code Segemnt 3


class OTPcontroller extends GetxController {
s t a t i c O T P c o n t r o l l e r g e t i n s t a n c e => Get . f i n d ( ) ;

void verifyOTP ( S t r i n g otp ) async {


var i s V e r i f i e d = await AuthenticationRepository .

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 ( ) ;
}
}

Listing 4: Code Segment 4


class AuthenticationRepository extends

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 ( ) ;

f i n a l auth = FirebaseAuth . instance ;


l a t e f i n a l Rx<U s e r ?> f i r e b a s e U s e r ;
var v e r i f i c a t i o n I d = ’ ’ . obs ;

@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 ( ) ) ;
}

F u t u r e <void > 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 ) a s y n c {


await a u t h . verifyPhoneNumber (
phoneNumber : mobileNo ,
v e r i f i c a t i o n C o m p l e t e d : ( c r e d e n t i a l ) async {
await auth . signInWithCredential ( c r e d e n t i a l ) ;
},
verificationFailed : (e) {
i f ( e . c o d e == ” i n v a l i d −phone − nember ” ) {
Get . s n a c k b a r ( ’ E r r o r ’ , ’ The number i s n o t v a l i d ’ ) ;
}
else {
Get . s n a c k b a r ( ’ E r r o r ’ , ’ S o m e t h i n g went wrong ,

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 ) ;
}
}

F u t u r e <void > l o g o u t ( ) a s y n c => a w a i t auth . signOut ( ) ;


}
}

Listing 5: Code Segemnt 5


c l a s s SignUpWithEmailAndPasswordFailure {
f i n a l S t r i n g message ;

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

already exists for

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 .

Please contact support . ’ ) ;


case ’ user − d i s a b l e d ’ :
return const
SignUpWithEmailAndPasswordFailure ( ’ This user has

been d i s a b l e d . P l e a s e c o n t a c t support for help . ’ ) ;


default :
return const SignUpWithEmailAndPasswordFailure ( ) ;
}
}
}

15

You might also like