This shows you the differences between two versions of the page.
Next revision | Previous revision Next revision Both sides next revision | ||
software_carpentary2 [2011/06/20 03:35] medhamsh created |
software_carpentary2 [2011/06/20 04:23] medhamsh |
||
---|---|---|---|
Line 3: | Line 3: | ||
The more you invest in quality, the less time it takes to develop working software.\\ | The more you invest in quality, the less time it takes to develop working software.\\ | ||
- | Quality is not just testing\\ | + | Quality is not just testing\\ |
- | + | Trying to improve the quality of software by doing more testing is like trying to lose weight by weighing yourself more often. (Steve McConnell)\\ | |
- | Trying to improve the quality of software by doing more testing is like trying to lose weight by weighing yourself more often. (Steve McConnell)\\ | + | |
Quality is: | Quality is: | ||
Line 17: | Line 16: | ||
* Suppose you have a function that compares two 7-digit phone numbers, and returns True if the first is greater than the second | * Suppose you have a function that compares two 7-digit phone numbers, and returns True if the first is greater than the second | ||
- | o 1072 possible inputs | + | * 1072 possible inputs |
- | o At ten million tests per second, that's 155 days | + | * At ten million tests per second, that's 155 days |
* If they're 7-character alphabetic strings, it's 254 years | * If they're 7-character alphabetic strings, it's 254 years | ||
o Then you move on to the second function... | o Then you move on to the second function... | ||
- | * And how do you know that your tests are correct? | + | * And how do you know that your tests are correct? |
* All a test can do is show that there may be a bug | * All a test can do is show that there may be a bug | ||
+ | ===== Nomenclature ===== | ||
+ | |||
+ | A unit test exercises one component in isolation | ||
+ | |||
+ | * Developer-oriented: tests the program's internals | ||
+ | |||
+ | An integration test exercises the whole system | ||
+ | |||
+ | * User-oriented: tests the software's overall behavior | ||
+ | |||
+ | Regression testing is the practice of rerunning tests to check that the code still works | ||
+ | |||
+ | * I.e., make sure that today's changes haven't broken things that were working yesterday | ||
+ | * Programs that don't have regression tests are difficult (sometimes impossible) to maintain | ||
+ | |||
+ | ===== Test results specifications ===== | ||
+ | |||
+ | Any test can have one of three outcomes: | ||
+ | |||
+ | * Pass: the actual outcome matches the expected outcome | ||
+ | * Fail: the actual outcome is different from what was expected | ||
+ | * Error: something went wrong inside the test (i.e., the test contains a bug) | ||
+ | o Don't know anything about the system being tested | ||
+ | |||
+ | A specification is something that tells you how to classify a test's result | ||
+ | |||
+ | * You can't test without some sort of specification | ||
+ | |||
+ | |||
+ | ===== Writing Tests ===== | ||
+ | How to write tests so that: | ||
+ | * It's easy to add or change tests | ||
+ | * It's easy to see what's been tested, and what hasn't | ||
+ | |||
+ | A test consists of a fixture, an action, and an expected result | ||
+ | o A fixture is something that a test is run on | ||
+ | o Can be as simple as a single value, or as complex as a networked database | ||
+ | Every test should be independent | ||
+ | o I.e., the outcome of one test shouldn't depend on what happened in another test | ||
+ | o Otherwise, faults in early tests can distort the results of later ones | ||
+ | So each test: | ||
+ | o Creates a fresh instance of the fixture | ||
+ | o Performs the operation | ||
+ | o Checks and records the result | ||
+ | |||
+ | Find the exercises at http://software-carpentry.org/3_0/qa.html | ||
+ | |||
+ | ====== Reading Code ====== | ||
+ | |||
+ | Read the following code and test! | ||
+ | |||
+ | <code> | ||
+ | void main() | ||
+ | { | ||
+ | char str[40]; | ||
+ | int i,flag=0,len; | ||
+ | clrscr(); | ||
+ | printf("\n Enter A string : "); | ||
+ | gets(str); | ||
+ | len=strlen(str); | ||
+ | for(i=0;i<(len/2);i++) | ||
+ | { | ||
+ | if(str[i]!=str[len-1-i]) | ||
+ | { | ||
+ | flag=1; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | if(flag==1) | ||
+ | { | ||
+ | printf(" \n The string is not palindrome"); | ||
+ | } | ||
+ | if(flag==0) | ||
+ | printf("\n String is palindrome"); | ||
+ | getch(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | void main() | ||
+ | { | ||
+ | char main_str[40],str[40]; | ||
+ | int i,j,len1,len2; | ||
+ | clrscr(); | ||
+ | printf("\n Enter the main String :"); | ||
+ | gets(main_str); | ||
+ | printf("\n enter the String you wanna search : "); | ||
+ | gets(str); | ||
+ | len1=strlen(main_str); | ||
+ | len2=strlen(str); | ||
+ | i=0; | ||
+ | j=0; | ||
+ | while(str[i]!='\0') | ||
+ | { | ||
+ | while(main_str[j]!='\0') | ||
+ | { | ||
+ | if(str[i]==main_str[j]) | ||
+ | { | ||
+ | i++; | ||
+ | if(len2==i) | ||
+ | { | ||
+ | j=j-len2+2; | ||
+ | printf("\n found at %d location",j); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | }//if | ||
+ | else | ||
+ | j++; | ||
+ | |||
+ | }//inner while | ||
+ | if(j==len1) | ||
+ | { | ||
+ | printf("\n not Found"); | ||
+ | break; | ||
+ | }//if | ||
+ | |||
+ | }//outer while | ||
+ | getch(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | void main() | ||
+ | { | ||
+ | int a,b; | ||
+ | clrscr(); | ||
+ | printf("\n enter First Number :"); | ||
+ | scanf("%d",&a); | ||
+ | printf("\n enter Second Number :"); | ||
+ | scanf("%d",&b); | ||
+ | swap(&a,&b); | ||
+ | printf("\n first Number is : %d",a); | ||
+ | printf("\n second Number is : %d",b); | ||
+ | getch(); | ||
+ | } | ||
+ | |||
+ | swap(int *a,int *b) | ||
+ | { | ||
+ | *a=*a-*b; | ||
+ | *b=*a+*b; | ||
+ | *a=*b-*a; | ||
+ | |||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | main() | ||
+ | { | ||
+ | int temps[31]; | ||
+ | int index,total; | ||
+ | float average,celsius; | ||
+ | total=0.0; | ||
+ | for(index=0;index<31;index++) | ||
+ | { | ||
+ | printf("enter temperature #%d:",index); | ||
+ | scanf("%d",&temps[index]); | ||
+ | } | ||
+ | for(index=0;index<31;index++) | ||
+ | total+=temps[index]; | ||
+ | average=total/31.0 | ||
+ | printf("average is:%f\n\n", average); | ||
+ | puts9"fahrenheit\tcelsius\n"); | ||
+ | for(index=0;index<31;index++) | ||
+ | { | ||
+ | celsius=(5.0/9.0)*(temps[index]-32); | ||
+ | printf("%d\t\t%6.2f\n",temps[index],celsius); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | #include "stdio.h" | ||
+ | main() | ||
+ | { | ||
+ | FILE*fp; | ||
+ | int letter; | ||
+ | if((fp=fopen("MYFILE","r"))==NULL) | ||
+ | { | ||
+ | puts("Cannot oepn the file"); | ||
+ | exit(); | ||
+ | } | ||
+ | while((letter=fgetc(fp)) !=eof) | ||
+ | printf("%c",letter); | ||
+ | fclose(fp); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ====== Make: Automated Builds ====== | ||
+ | |||
+ | The make utility | ||
+ | |||
+ | If you run | ||
+ | |||
+ | <code> | ||
+ | make | ||
+ | </code> | ||
+ | |||
+ | this program will look for a file named makefile in your directory, and then execute it. | ||
+ | If you have several makefiles, then you can execute them with the command: | ||
+ | |||
+ | <code> | ||
+ | make -f MyMakefile | ||
+ | </code> | ||
+ | |||
+ | There are several other switches to the make utility. For more info, man make. | ||
+ | |||
+ | ===== Build Process ===== | ||
+ | |||
+ | |||
+ | 1. Compiler takes the source files and outputs object files | ||
+ | 2. Linker takes the object files and creates an executable | ||
+ | |||
+ | ==== Compiling by hand ==== | ||
+ | |||
+ | |||
+ | The trivial way to compile the files and obtain an executable, is by running the command: | ||
+ | <code> | ||
+ | g++ main.cpp hello.cpp factorial.cpp -o hello | ||
+ | </code> | ||
+ | |||
+ | ==== The basic Makefile ==== | ||
+ | |||
+ | |||
+ | The basic makefile is composed of: | ||
+ | |||
+ | <code> | ||
+ | target: dependencies | ||
+ | [tab] system command | ||
+ | </code> | ||
+ | |||
+ | This syntax applied to our example would look like: | ||
+ | |||
+ | <code> | ||
+ | all: | ||
+ | g++ main.cpp hello.cpp factorial.cpp -o hello | ||
+ | </code> | ||
+ | |||
+ | ==== Using variables and comments ==== | ||
+ | |||
+ | You can also use variables when writing Makefiles. It comes in handy in situations where you want to change the compiler, or the compiler options. | ||
+ | <code> | ||
+ | # I am a comment, and I want to say that the variable CC will be | ||
+ | # the compiler to use. | ||
+ | CC=g++ | ||
+ | # Hey!, I am comment number 2. I want to say that CFLAGS will be the | ||
+ | # options I'll pass to the compiler. | ||
+ | CFLAGS=-c -Wall | ||
+ | |||
+ | all: hello | ||
+ | |||
+ | hello: main.o factorial.o hello.o | ||
+ | $(CC) main.o factorial.o hello.o -o hello | ||
+ | |||
+ | main.o: main.cpp | ||
+ | $(CC) $(CFLAGS) main.cpp | ||
+ | |||
+ | factorial.o: factorial.cpp | ||
+ | $(CC) $(CFLAGS) factorial.cpp | ||
+ | |||
+ | hello.o: hello.cpp | ||
+ | $(CC) $(CFLAGS) hello.cpp | ||
+ | |||
+ | clean: | ||
+ | rm -rf *o hello | ||
+ | </code> |