Monday, September 11, 2017

trying to write test cases for each and every line

Leave a Comment
  • have written test case for jumping method,
  • but its not going inside onloadend method seat.onloadend, when I see code coverage report.
    • in createSpyObj i called loadend but still its not going inside
  • can you guys tell me how to fix it.
  • providing my code and test case below.
  • I am trying to wite test case for each and every line.
  jumping(inputValue: any): void {     var that = this;     var file: File = inputValue.files[0];      var seat: FileReader = new FileReader();     seat.onloadend = (e) => {       this.encodeBase64 = seat.result;       that.fileSelect = $("#laptop").val().replace(/^.*\\/, "");       if (that.fileSelect == '') {         that.dragDrop = that.swimming;       } else {         that.dragDrop = "";         that.dragDrop = that.fileSelect;       }     }     $('.running').show();     if (inputValue.files.length > 0) {       var wholeQuantity = 0;        wholeQuantity = inputValue.files[0].size / 1048576; //size in mb         if (wholeQuantity > 5) {         $('.stars').show();         $("#laptop").val('');         this.fileSelect = "";       }        seat.readAsDataURL(file);     }     }       describe('Jasmine Unit Tests: hand-Basketball-Manage-mobiles', () => {     let rainSPORTSService:SPORTSService;     let SPORTSService: SPORTSService;     let decodeService: DecodeService;     let BasketballChainComponent: handBasketballChain;     let kickViewrainsComponent: kickViewrains;     let tiger: Componenttiger<handBasketballChain>;     let raintiger: Componenttiger<kickViewrains>;     let foodktiger: Componenttiger<foodkCarousel>;     let kendotiger: Componenttiger<KendoGridComponent>;     let foodkComponent:foodkCarousel;     let kendoComponent:KendoGridComponent;     beforeEach(async(() => {      jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;      TestBed.configureTestingModule({       imports: [HttpModule, FormsModule,BrowserModule ],       declarations:[handBasketballChain, KendoGridComponent,ProgressCircle,             kickViewrains,handLeftSliderComponent,foodkCarousel,kickmobiles],       providers:[SPORTSService,DecodeService,recentPinnedHistoryService,         {provide: Router, useClass: RouterModule}, validationService,saveService,         ChainService]      }).compileComponents().then(() =>{         foodktiger = TestBed.createComponent(foodkCarousel);         kendotiger = TestBed.createComponent(KendoGridComponent);         foodkComponent = foodktiger.componentInstance;         kendoComponent = kendotiger.componentInstance;         tiger = TestBed.createComponent(handBasketballChain);         BasketballChainComponent = tiger.componentInstance;         SPORTSService = tiger.debugElement.injector.get(SPORTSService);         tiger.componentInstance.kickmobiles.SPORTSService=tiger.debugElement.injector.get(SPORTSService);         tiger.componentInstance.kickViewrains.SPORTSService=tiger.debugElement.injector.get(SPORTSService);         decodeService = tiger.debugElement.injector.get(DecodeService);         BasketballChainComponent.inputfoodkCarousel = foodkComponent; //jasmine.createSpy('foodkCarousel');//.andCallFake(function(msg) { return this });         BasketballChainComponent.kickmobiles.gridkendo=kendoComponent;         })}     ));        it('Read kick mobile', (done) => {           let callFirstTime : boolean = true;         let url=          spyOn(BasketballChainComponent.kickmobiles.SPORTSService,'getResponse').and.             callFake(() => {                      if(callFirstTime){                         callFirstTime = false; // Invoked by detectChanges()                          return Observable.of([{         "mobileId": "100",         "mobileName": "http://localhost:3000/assets/js/actualairings.json",         "mobileType": "TITLE",         "mobileData": "YWZjYXJlZ2Vyamh2dmFyZWdoYnZi",         "notes": "",         "notesId": "100",         "elfDocID": "100",         "url": "http://localhost:3000/upload",         "date": "06/27/2017",         "addedByName": "Kamal",         "userID": "206509786",         "operationType": "create"       }]                     );                     }              });               const fileReaderSpy = jasmine.createSpyObj('FileReader', ['readAsDataURL', 'onloadend']);             spyOn(window, 'FileReader').and.returnValue(fileReaderSpy);              BasketballChainComponent.kickmobiles.jumping({                 files: "Untitled-2.txt"             });              var seat = new FileReader();              //seat.onloadend(e);              //BasketballChainComponent.kickmobiles.jumping.onloadend()               tiger.whenStable().then(() => {                 done();             });       });        }); 

1 Answers

Answers 1

Remember, the key to Unit Testing is to write small testable Units of code. You're on the right track for the most part, stubbing FileReader and so forth before calling the 'jumping' function.

Here's the thing though, when you create your dummy FileReader it never calls 'onloadend' because the mock/stub doesn't have that event and eventing system implemented.

From a test perspective your current code needs a small refactor to become testable. The 'jumping' function relies on a nested arrow function attached to onloadend. Now your code has a direct call to that commented out in the test, I'm a little surprised that didn't work to be honest and would suggest perhaps making sure your code coverage tool (probably Instanbul if you're using Jasmine) is configured correctly.

With the above aside, you should refactor that nested function and instead create a named function that you can then call directly for your unit tests.

This is an (untested on my end) example of a better way to implement your function.

jumping(inputValue: any): void {     var that = this;     var file: File = inputValue.files[0];      var seat: FileReader = new FileReader();     // bind the arguments for the event handler, first arg will be 'this' of the     // loaded named function     // second is 'that' variable, seat is seat and the final 'e' variable is     // implicit and shouldn't be specified.     seat.onloadend = loaded.bind(seat, that, seat);       $('.running').show();     if (inputValue.files.length > 0) {         var wholeQuantity = 0;          wholeQuantity = inputValue.files[0].size / 1048576; //size in mb          if (wholeQuantity > 5) {             $('.stars').show();             $("#laptop").val('');             this.fileSelect = "";         }          seat.readAsDataURL(file);     } }  loaded(that: any, seat: any, e: any): void { // now a testable named function     this.encodeBase64 = seat.result;     that.fileSelect = $("#laptop").val().replace(/^.*\\/, "");     if (that.fileSelect == '') {         that.dragDrop = that.swimming;     } else {         that.dragDrop = "";         that.dragDrop = that.fileSelect;     } } 

An example of a test that will cover all the lines of code of the 'loaded' function as written above is as follows:

describe('test suite', function () { var old$ = $;  afterEach(function () {     $ = old$; });  it('covers all lines and else path on if but does not actually test anything', function () {     $ = function () {         val: function () {             return 'Untitled-2.txt';         }     }; // stub JQuery      var seat = {         result: 'Base64encoded'     };     var scope = {};     var that = {         swimming: false,         dragDrop: null     };      BasketballChainComponent.kickmobiles.loaded.call(scope, that, seat, null); });  it('covers all lines and on if but not else and does not actually test anything', function () {     $ = function () {         val: function () {             return '';         }     }; // stub JQuery      var seat = {         result: 'Base64encoded'     };      var scope = {};      var that = {         swimming: false,         dragDrop: null     };      BasketballChainComponent.kickmobiles.loaded.call(scope, that, seat, null); }); 

});

Now please take note, in the real world you should never write tests just for code coverage that do not actually test the given functions. It will lead you into a false sense of security and not actually TEST your code.

An analogy would be as follows:

You're working as a car crash tester. Your job is to verify the car is safe in a crash. So a car is crashed at 10 km/h and you need to check it over.

You take a check list of things that you need to confirm. So in a 10 km/h crash you only expect paint to be scratched. So you look at the paint, if the paint is scratched but there's no other damage, the test passes. If the car is dented, the test fails.

That's a good test overall as it is testing something quantifiable and it's testing an intention.

What you're doing by trying to achieve 100% code coverage without actually testing functionality is crashing the car and then not verifying anything.

You're saying "Well I crashed the car, I don't really need to check it did what it's supposed to do in a crash so long as I crashed it right?".

Sure, you got 100% crash coverage by looking at the car, but by not actually testing it, you may as well not have even bothered.

I hope this helps you understand Unit Testing as a concept a little better.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment