-
-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to use mocks with angular TestBed #27
Comments
Can you make an isolated example and upload it as a zip file? |
Sure here is isolated example Its ng new with 3 files: |
I encountered a similar problem. Declaring return values for each method/property on the mock that is used by the test should solve it. I think this is kinda an architectural issue with this lib. |
@domasx2 not a bad idea. What about calling
Or something similar? |
yeah but that would require you to build a fake before you initailize testbed i usually start mocking functions in tests (as those are case specyfic) not in beforeeach statments. |
Why would it require you to build them before? |
The exception from JitEmitterVisitor happens during testbed configureTestingModule with mostly done in beforeeach statments of the test.spec. |
When I switched from AngularJS to Angular on release of v2 I tried to use my own library jsSubstitute for mocking services and the conclusion I came to was that it just isn't necessary and using anything other than the default Jasmine spies isn't worth the grief and effort when testing Components. Don't get me wrong I think substitute.js is a great improvement on the other libraries targeting TypeScript (including my own) but for testing Angular Components I don't think a library is the way to go. When testing Angular services, yes libraries can be helpful since these are typically just tests that exercise the Class. After trying several solutions I settled for simply providing services in the test module then using TestBed.get(MyService) to get an instance in the test via DI and using Jasmine spyOn to mock just the part/s of the service I am going to touch during the particular test. I know this doesn't provide a solution, but I would prefer that this library stay true to the fluent and readable NSubstitute pattern rather than going down the route of having to use an .Object property or calling a method to pre-build a substitute. |
I would argue here. Spies are not mocks and they break isolation of unit tests. Components should be tested the same way as services are. This lib was compared with ts-mockito and i would favored it over ts-mockito as its more simple (we use nsubstitute on backend testing). But since im unable to test components with it i thnik its not worth testing with 2 frameworks. btw ts-mockito support testing components anyway thanks for providing answer i though im missing sth simple. |
Argument accepted, but the whole philosophy behind NSubstitute is that the formal differences between, Mock, Stub, Fake, Spy etc don't matter if it lets you substitute a real element (class, method, function etc) with something else to enable testing then that is what matters. Whilst I welcome the ability to work with JS/TS as if it were strongly typed it isn't and I prefer to embrace that we can do some things more easily because of the dynamic nature of the language, and for me Spies are an acceptable compromise and qualify as a form of Substitute. I looked at ts-mockito and rejected it because like all similar frameworks other than NSubstitute/Substitute they force you to write messy ugly test code. The elegance of the NSubstitute approach for me is so much more natural and readable. So I am really happy that this library exists, and hope it doesn't get drawn into copying patterns from other libraries. |
Hi @ffMathy At the begining I'd like to thank you for great work you've done! ;) I would like use it with angular project and run into the same issue. After some debugging the problem is with angular JIT compilation. Sample:
When anuglar try to createComponent execute:
And this proxy is casting to string. I have two ways to resolve it:
@ffMathy maybe is good idea to add framework specify wrappers like or maybe is better way to accomplish this? Best regards! |
Great idea @Karql! |
@ffMathy for my purposes I've done something like this: Set Properly this property should be set to undefined but then promise is pass to stringify method. So next step will be set returns for "overridenName", and "name". I hope this info will help you a bit ;) |
It sure does @Karql! I'll take a look as soon as I have the time. Won't be for the next month or so I think. I think I'll end up creating different integrations for substitute.js, for instance @fluffy-spoon/substitute-angular, which you can then "hook in" to substitute.js to support these cases. |
I got a workaround that allows to inject substitutes as providers using the TestBed. Defining the substitute provider resolution by value ('useValue') like this does not work indeed: //
// Not working example because the provider is resolved by 'useValue'
//
describe('My test', () => {
let sampleListService: SubstituteOf<SampleListService>();
beforeEach(() => {
sampleListService = Substitute.for<SampleListService>();
TestBed.configureTestingModule({
declarations: [ SampleListComponent ],
providers: [
{ provide: SampleListService, useValue: sampleListService }
]
})
.compileComponents();
});
}); But... what works is to setup the provider resolution by factory like that: //
// Working example because the provider is resolved by 'useFactory'
//
describe('My test', () => {
let sampleListService: SubstituteOf<SampleListService>();
beforeEach(() => {
sampleListService = Substitute.for<SampleListService>();
TestBed.configureTestingModule({
declarations: [ SampleListComponent ],
providers: [
{ provide: SampleListService, useFactory: () => sampleListService }
]
})
.compileComponents();
});
}); For the sake of brievety: Replace { provide: SampleListService, useValue: sampleListService } By { provide: SampleListService, useFactory: () => sampleListService } And it should work. I'm using Jest as test framework with Angular 7. Hope it helps ! |
Love the simplicity of lib but im unable to use it in component testing with angular TestBed.
Test:
Not sure if am doing sth wrong but i get following exception.
TypeError: Cannot convert object to primitive value at JitEmitterVisitor._emitReferenceToExternal (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4693:44) at JitEmitterVisitor.visitExternalExpr (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4662:1) at ExternalExpr.visitExpression (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:1293:1) at visitAllObjects.expr (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4387:1) at JitEmitterVisitor.visitAllObjects (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4406:1) at JitEmitterVisitor.visitAllExpressions (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4387:1) at JitEmitterVisitor.visitInvokeFunctionExpr (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4218:1) at JitEmitterVisitor.visitInvokeFunctionExpr (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4547:1) at InvokeFunctionExpr.visitExpression (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:1250:1) at visitAllObjects.expr (http://localhost:9876/node_modules/@angular/compiler/fesm2015/compiler.js?:4387:1)
The text was updated successfully, but these errors were encountered: