试图为每一行编写测试用例 [英] trying to write test cases for each and every line
问题描述
- 已为跳跃方法编写了测试用例,
- 但是当我看到代码覆盖率报告时,它不在onloadend方法seat.onloadend内部.
-
- 在createSpyObj中,我调用了loadend,但仍然没有进入
- 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
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(); }); }); });
推荐答案
Remember, the key to Unit Testing is to write small testable Units of code.Unit Testing - Wikipedia
在大多数情况下,您会在正确的轨道上进行操作,在调用跳转"功能之前先对FileReader进行诸如此类的操作.这是测试依赖于另一个外部库/函数/框架的代码的方式.维基百科页面上有关单元测试状态的相关部分
You're on the right track for the most part, stubbing FileReader and so forth before calling the 'jumping' function. This is very much the way to test code that relies on another external library/function/framework. The relevant portion of the Wikipedia page for Unit Testing states
由于某些类可能引用了其他类,因此测试一个类可能经常溢出到测试另一个类中.一个常见的例子是依赖于数据库的类:为了测试该类,测试人员经常编写与数据库交互的代码.这是一个错误,因为单元测试通常不应超出其自身的类边界,并且尤其不应越过此类过程/网络边界,因为这会给单元测试套件带来无法接受的性能问题.
Because some classes may have references to other classes, testing a class can frequently spill over into testing another class. A common example of this is classes that depend on a database: in order to test the class, the tester often writes code that interacts with the database. This is a mistake, because a unit test should usually not go outside of its own class boundary, and especially should not cross such process/network boundaries because this can introduce unacceptable performance problems to the unit test-suite.
这就是问题,当您创建虚拟FileReader或模拟文件时,它永远不会调用"onloadend",因为模拟/存根没有实现该事件和事件系统.这意味着您的模拟是不完整的. Wikipedia声明
Here's the thing though, when you create your dummy FileReader or mock it never calls 'onloadend' because the mock/stub doesn't have that event and eventing system implemented. This means the mock is incomplete on your part. Wikipedia states
相反,软件开发人员应围绕数据库查询创建一个抽象接口,然后使用其自己的模拟对象实现该接口.通过从代码中抽象出这种必要的附件(暂时减少净有效耦合)
Instead, the software developer should create an abstract interface around the database queries, and then implement that interface with their own mock object. By abstracting this necessary attachment from the code (temporarily reducing the net effective coupling)
就您而言,不是模拟数据库,而是模拟FileReader loadend事件.
In your case, rather than a database, you'd be mocking the FileReader loadend event.
从测试的角度来看,您当前的代码需要进行小的重构才能变得可测试.单元测试的总体目标是隔离测试小型功能单元.
From a test perspective your current code needs a small refactor to become testable. The general objective of Unit Tests is to test small units of functionality in isolation.
单元测试的目的是隔离单元并验证其正确性.
The objective in unit testing is to isolate a unit and validate its correctness.
跳转"功能依赖于附加到onloadend的嵌套箭头功能.您的代码直接调用了测试中注释掉的代码,说实话,这让我感到有些惊讶,这并没有使您的代码覆盖率提高,并且可能会建议您确保您的代码覆盖率工具,如果您愿意的话,可能是伊斯坦布尔使用Jasmine的配置正确.
The 'jumping' function relies on a nested arrow function attached to onloadend. Your code has a direct call to that commented out in the test, I'm a little surprised that didn't work to up your code coverage to be honest and would suggest perhaps making sure your code coverage tool, probably Istanbul 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); });
});
现在请注意,在现实世界中,您绝不应该只为未实际测试给定功能的代码覆盖范围编写测试.这会使您产生一种错误的安全感,而不是真正 TEST . MSDN 的意思是:
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. The MSDN has this to say:
单元测试的主要目标是采用应用程序中最小的可测试软件,将其与其余代码隔离,并确定其行为是否完全符合您的预期.
The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect.
与您正在做的事情类似,如下所示:
An analogy of what you're doing would be as follows:
您正在作为汽车碰撞测试仪.您的工作是验证汽车在碰撞中是否安全.因此,汽车以每小时10公里的速度坠毁,您需要检查一下.
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.
您会列出需要确认的事项清单.因此,在10 km/h的车祸中,您只希望油漆被刮擦.因此,您要看一下油漆,如果油漆被刮擦但没有其他损坏,则测试通过.如果汽车凹进去,则测试失败.
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.
您试图在没有实际测试功能的情况下实现100%的代码覆盖率的做法是在撞车,然后不进行任何验证.
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?".
当然,通过查看汽车,您可以获得100%的碰撞覆盖率,但是通过不进行实际测试,您甚至都不会打扰.代码覆盖率是用于发现未经测试的代码的有用工具,它不能用于获取获得完整代码覆盖率的任意度量.对此的进一步阅读和出色的文章可以在破损的承诺中进行阅读. 100%的代码覆盖率
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. Code coverage is a useful tool for spotting code that isn't tested, it's not used to achieve the arbitrary metric of gaining full code coverage. Further reading on this and an excellent write up can be read at Broken promise of 100% code coverage
本质上是症结所在
易于测量的代码覆盖率这一事实并不能使其成为一个很好的指标.即使您的代码覆盖率为100%,您也可能会遇到麻烦.
The fact that it is easy to measure code coverage doesn’t make it a good metric though. You can get into trouble even if your code coverage is 100%.
我从中篇文章中省略了代码,但继续说明:
I've omitted the code from the medium article, however it goes on to state:
此单元测试可为elementAtIndex:函数提供完美的100%测试覆盖率. 是否证明该功能正常工作?答案显然是不.当我们超出数组边界时会发生什么? 为什么会这样呢?当您尝试着眼于代码覆盖率指标时,您将编写代码来查看测试功能/方法的实现.但是,尚未证明该实现是正确的.这就是我们要测试它的原因. 即使功能如此简单,代码覆盖率仍然无法作为衡量单元测试质量的良好指标.
This unit test produces the perfect 100% test coverage for the elementAtIndex: function. Does it prove that the function works correctly? The answer is, obviously, no. What happens when we exceed the array boundaries? Why did that happen? When you try to focus on the code coverage metric you write code that looks at the implementation of the tested function/method. But the implementation is not proven to be correct yet. That is the reason why we want to test it. Even with that simple function code coverage failed as a good metric to measure the quality of unit-tests.
此外,在上面我声明您应该测试代码的意图. 中型"文章也对此进行了说明.
Further, above I state that you should test the intention of your code. The Medium article also states this.
该怎么办?不要看该方法的实际实现,而要看合同.准确查看功能/方法的任何特定输入的输出.查看此函数执行或使用的副作用.考虑到可能存在的可能的极端情况.列出这些信息并据此进行测试.
What to do instead? Don’t look at the actual implementation of the method, look at the contract instead. Look precisely at the outputs of the function/method for any specific inputs. Look at the side-effects that this function does or uses. Take into account the possible edge cases that might exist. List this information and make tests according to that.
记住 100%的代码覆盖率并不意味着您的代码是100%正确的.
我希望这可以帮助您更好地理解单元测试.
I hope this helps you understand Unit Testing as a concept a little better.
这篇关于试图为每一行编写测试用例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!