Faking a module in angular 2 test - unit-testing

I have a function in angular 2 service which I would like to test.
service.ts
upload(){
let file = new Transfer();
file.upload(myfile).then( // my callback );
}
I would like to mock Transfer in my test using jasmine. I tried this in my
sevice.spec.ts
import { TransferMock as Transfer } from '../mocks/mocks' to mock it. But it is not working. This is how my test is instantiated .
describe('authentication service' , () => {
beforeEach(() => {
auth = new Service(<any>new HttpMock(), <any>new StorageMock())
});
it('initialize authentication',() => {
expect(auth).not.toEqual(null);
auth.upload('file'); //it fails here
});
})
edit
Transfer is not injected in the service. Only one function uses Transfer . So not injecting can reduce the initial loading time of the app i guess(would be happy to know other opinions) . So I would like to know if there is anyway to mock if its constructed this way ?
edit
Although I had accepted Martin's answer as it is the best practice, it has one issue which can happen when you use ionic-native plugins.If the plugin doesnt have browser support it can fail. In this case it happened when I inject it, with error FileTransfer is not defined . So I am back again, looking for suggestions.

In order to provide a mock for a class in a test, you need to inject the class in your implementation.
In your ngModule add Transfer to your providers. Then simply inject it into your service.
Then in your test you can use { provide: Transfer, useClass: TransferMock } in your TestBed providers.
Update
The primary purpose of Dependency Injection is to make code testable and to allow mocking - faking - stubbing of services.
Update
With Dependancy Injection you can configure a different set of providers for different environments.
For example, if you are running your application in the browser, and in a native mobile environment you can swap out your configuration.
In your module you could have something like this:
const TRANSFER_PROVIDER: any;
if (environment.browser) {
TRANSFER_PROVIDER = Transfer;
} else {
TRANSFER_PROVIDER = { provide: Transfer, useClass: NativeTransfer }
}
...
providers: [ TRANSFER_PROVIDER ]
NativeTransfer could be a simple stub that does nothing but prevent errors, or it could let the user know that this feature is not supported in their browser.

Related

Nestjs overrideProvider vs provider in unit testing

I see two ways of mocking services in NestJS for unit testing, the first one is the same as we define providers in real modules like:
const module = await Test.createTestingModule({
providers: [
UserService,
{
provide: getRepositoryToken(User),
useValue: mockUsersRepository,
}
],
}).compile();
And the other way with overrideProvider method. As following:
const module = await Test.createTestingModule({
imports: [UserModule]
})
.overrideProvider(getRepositoryToken(User))
.useValue(mockUsersRepository)
.compile();
What is the difference?
So let me try to explain it this way:
overrideProvider is useful when you've imported an entire module and need to override something it has as a provider. A use case, like the answer mentioned, would be overriding a logger. So say you have
const modRef = await Test.createTestingModule({
import: [AuthModule]
}).compile();
And assume that AuthModule has imports: [ LoggerModule ]. In our test, we don't really want to see all the logs created, but we can't provide a custom provider for the LoggerService because it's being imported and used via the LoggerModule (overriding an injection token isn't really a common practice). So to provide our own implementation forLoggerService (let's say we just need a noop log method) we can do the following
const modRef = await Test.createTestingModule({
import: [AuthModule]
})
.overrideProvider(LoggerService)
.useValue({ log: () => { /* noop */ } })
.compile();
And now when our AuthService calls this.logger.log() it will just call this noop and be done with it.
On the flip side, if we're doing unit testing, usually you don't need to overrideProvider because you just set up the provider and the custom provider directly in the testing module's metadata and use that.
The overrideProvider is really useful when you have to use imports (like integration and e2e tests), otherwise, generally, it's better to use a custom provider
The difference is pretty simple.
With the first approach (array of providers), you create custom testing module to test (probably) the UserService.
With second approach, you use complete module in the very same shape as it is used in the application itself.
The result is exactly the same - your mock is being injected into the constructor of UserService.
The first approach is better for small, mostly unit tests, but these tests can be also done without using NestJS test tooling at all (just pass mock manually to the ctor), while the second one does a great job in integration tests.
Repository is not great example to use to explain, but think about Logger.
You are performing some integration tests of 2 or more modules.
You do not want to manually create big testing module (which also is breaking the connection with real shape of your modules), but you want to just import your modules which are being tested together and .overrideProvider for Logger with e.g. loggerMock which lets you to assert all logger calls across all tested modules.
Example:
#Module({providers: [LoggerService], exports: [LoggerService]})
export class LoggerModule {}
#Module({imports: [LoggerModule], providers: [FooService]})
export class FooModule {}
#Module({imports: [LoggerModule], providers: [BarService]})
export class BarModule {}
#Module({imports: [FooModule, BarModule]}
export class AppModule {}
// TEST
const testModule = await Test.createTestingModule({
import: [AppModule]
})
.overrideProvider(LoggerService)
.useValue(/* your logger mock will be provided in both FooService and BarService and you can easily test all related to logs then */)
.compile();
I hope it is clear. If not, please leave a comment and I will try to explain more.

How best to unit test a ServiceStack service that uses IServiceGateway to call other internal services

I've been following the guidelines here - https://docs.servicestack.net/testing
I'm trying to do unit testing rather than integration, just to cut down the level of mocking and other complexities.
Some of my services call some of my other services, via the recommended IServiceGateway API, e.g. Gateway.Send(MyRequest).
However when running tests i'm getting System.NotImplementedException: 'Unable to resolve service 'GetMyContentRequest''.
I've used container.RegisterAutoWired() which is the service that handles this request.
I'm not sure where to go next. I really don't want to have to start again setting up an integration test pattern.
You're likely going to continually run into issues if you try to execute Service Integrations as unit tests instead of Integration tests which would start in a verified valid state.
But for Gateway Requests, they're executed using an IServiceGateway which you can choose to override by implementing GetServiceGateway() in your custom AppHost with a custom implementation, or by registering an IServiceGatewayFactory or IServiceGateway in your IOC, here's the default implementation:
public virtual IServiceGateway GetServiceGateway(IRequest req)
{
if (req == null)
throw new ArgumentNullException(nameof(req));
var factory = Container.TryResolve<IServiceGatewayFactory>();
return factory != null ? factory.GetServiceGateway(req)
: Container.TryResolve<IServiceGateway>()
?? new InProcessServiceGateway(req);
}
Based on the discussion in the answer by #mythz, this is my solution:
Use case like OP: Test the "main" service, and mock the "sub service", and like OP I'd want to do that with Unit test (so BasicAppHost), because it's quicker, and I believe it is easier to mock services that way (side note: for AppHost based integration test, SS will scan assemblies for (real) Services, so how to mock? Unregister from "container" and replace w. mock?).
Anyway, for the unit test:
My "main" service is using another service, via the IServiceGateway (which is the officially recommended way):
public MainDtoResponse Get(MainDto request) {
// do some stuff
var subResponse = Gateway.Send(new SubDto { /* params */ });
// do some stuff with subResponse
}
In my test setup:
appHost = new BasicAppHost().Init();
var mockGateway = new Mock<IServiceGateway>(); // using Moq
mockGateway.Setup(x => x.Send<SubDtoResponse>(It.IsAny<SubDto>()))
.Returns(new SubDtoResponse { /* ... */ });
container.Register(mockGateway.Object);
So the IServiceGateway must be mocked, and then the Send method is the important one. What I was doing wrong was to mock the service, when I should have mocked the Gateway.
Then call the main service (under test) in the normal fashion for a Unit Test, like in the docs:
var s = appHost.Container.Resolve<MainService>(); // must be populated in DI manually earlier in code
s.Get(new MainDto { /* ... */ })
PS: The mockGateway.Setup can be used inside each test, not necessarily in the OneTimeSetUp.

Checking middleware is called from http call

How would one test that a piece of custom middleware is actually called from a standard HTTP event?
ie. The middleware is called from:
MyController.js
router.get('/some/endpoint', [myMiddleware()], (req, res, next) => {
// Code to do whatever here
});
The middleware itself can be defined as:
MyMiddleware.js
module.exports = () => {
// Middleware code in here
}
My quest is to check that the middleware is called once from my unit test, but I cannot find documentation around this.
MyTest.test.js
it('Should return whatever from GET call', () => {
return request(app).get('/some/endpoint')
.expect(200)
.expect(res => {res.body.should.deep.equal(bodyValue)});
// How would I place code in here to check that MyMiddleware is called?
// ie. sinon.assert.calledOnce(MyMiddleware)
});
I have thought about using Sinon's spy, but I can't think of how to hook into the middleware... My attempt was this:
const mwSpy = sinon.spy(require('path to middleware file'));
sinon.assert(calledOnce(mwSpy));
The usual way of going about this is splitting this into two tests, an integration test and a unit test.
Will the middleware I specified in the router.get call end up being called when someone hits this endpoint?
Does my middleware do the right thing?
The first part is basically testing that the Express API is doing what the documentation says. That's not what unit tests are for (this was tagged unit-testing), but since you are already using HTTP requests to test the endpoint, I guess that's not what you are after anyway: you are basically creating verification tests for your system.
You could still test the Express routing without HTTP, though, as I detail in the answer to this question, concerning how to test the router programmatically (faster tests, no http), but less just stick to what you have.
So the basic question is: "My quest is to check that the middleware is called once from my unit test". You don't seem to concern yourself with whether the middleware is doing the right thing or not, just that it's called, which calls for the question on whether we should test the middleware or the layer using the middleware.
In both cases, you need to find a way of injecting a test spy. Either you write a small utility method that will inject that spy: function setMiddleware(module){ middleware = module; } or you use some tooling like proxyquire. See this tutorial on Sinon's homepage for background.
I would just do this (in the test code):
it('Should return whatever from GET call', () => {
var middlewareFake = sinon.fake();
// I am assuming it's the actual app object you are referencing below in the request(app) line
var app = proxyquire('../app/index.js', { './my-middleware': middlewareFake });
//
return request(app).get('/some/endpoint')
.expect(200)
.expect(res => {
res.body.should.deep.equal(bodyValue)
expect(middlewareFake).was.called;
});
});

How can globally I mock/replace components in integration tests?

I have a component "nested" which makes a web request, and I'm using this component from another component "parent".
I'm trying to write some integration tests for "parent", but they are failing as the "nested" component's web requests are failing.
Instead of mocking out the requests, I was just hoping to mock some of the "nested" functionality to prevent the web request. This is easily achievable with reopen, but of course this will cause the tests for "nested" to fail.
Does anyone know if there is a way that I can either stub pieces of "nested", or maybe use the registry to replace "nested" with an extended class?
To swap out a component, just for the purpose of a single test module, simply register a custom component to replace the original (only for the scope of the test module):
moduleForComponent('component-under-test', 'description', {
integration: true,
beforeEach() {
this.container.registry.register('component:nested-component', NestedComponent.extend({
modifiedFunction() {
}
}));
}
});

Laravel 5 isolated controller testing

I'm trying to unit test my controllers in Laravel 5, but have serious issues wrapping my head around it. It seems as I have to trade the great short-hand functions and static classes for dependency injected equivalents if I actually want to do isolated unit testing.
First off, what I see in the documentation as "Unit testing", is not unit testing to me. It seems more like functional testing. I can not test a controller function isolated, as I will have to go through the entire framework, and will need to actually seed my database if I have any code interacting with my database.
So, in turn, I want to test my controllers isolated of the framework. This is however proving to be quite difficult.
Let's look at this example function (I've kept out some parts of this function for the sake of the question):
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath());
}
}
Now, the problem arises in the final lines. Sure, I can mock the Request instance that's sent to the function, that's no issue. But how am I going to mock the Auth class, or the redirect function? I need to rewrite my class/function with dependency injection like this:
private $auth;
private $redirector;
public function __construct(Guard $auth, \Illuminate\Routing\Redirector $redirector)
{
$this->auth = $auth;
$this->redirector = $redirector;
}
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials, $request->has('remember')))
{
return $this->redirector->intended($this->redirectPath());
}
}
And I end up with a convoluted unit test, full of mocks:
public function testPostLoginWithCorrectCredentials()
{
$guardMock = \Mockery::mock('\Illuminate\Contracts\Auth\Guard', function($mock){
$mock->shouldReceive('attempt')->with(['email' => 'test', 'password' => 'test'], false)->andReturn(true);
});
$redirectorMock = \Mockery::mock('\Illuminate\Routing\Redirector', function($mock){
$mock->shouldReceive('intended')->andReturn('/somePath');
});
$requestMock = \Mockery::mock('\Illuminate\Http\Request', function($mock){
$mock->shouldReceive('only')->with('email', 'password')->andReturn(['email' => 'test', 'password' => 'test']);
$mock->shouldReceive('has')->with('remember')->andReturn(false);
});
$object = new AuthController($guardMock, $redirectorMock);
$this->assertEquals('/somePath', $object->postLogin($requestMock));
}
Now, if I had any more complex logic that would, for example, use a model, I'd have to dependency inject that as well, and mock it in my class.
To me, it seems like either, Laravel isn't providing what I want it to do, or my testing logic is flawed. Is there any way I can test my controller functions without getting out-of-control testing functions and/or having to depedency inject standard Laravel classes, available to me anyways in my controller?
You shouldnt be trying to unit test controllers. They are designed to be functional tested via calling them through the HTTP protocol. This is how controllers are designed, and Laravel provides a number of framework assertions you can include in your tests to ensure they work as expected.
But if you want to unit test the application code contained within the controller, then you should actually consider using Commands.
Using Commands allows you to extracte the application logic from your controller into a class. You can then unit test the class/command to ensure you get the results expected.
You can then simply call the command from the controller.
In fact the Laravel documentation tells you this:
We could put all of this logic inside a controller method; however, this has several disadvantages... it is more difficult to unit-test the command as we must also generate a stub HTTP request and make a full request to the application to test the purchase podcast logic.