Jasmine | How to test if any object is an array - unit-testing

I am migrating my angular application from the Mocha, Sinon, and Chai framework to Jasmine.
In Chai/Moch we do have something 'expect(result).to.be.an('array').that.include('XYZ');'
How to check 'Array' in Jasmine? For the array content check, I know 'toContain' will work fine but couldn't find any solution for 'Array' check.
I really appreciate any help you can provide.

In Jasmine, .toBe does a reference check and .toEqual does an equality check. Most times when asserting array or object types, you would want to use .toEqual.
const a = [];
const b = a;
const c = [];
expect(a).toBe(b); // passes
expect(a).toBe(c); // fails
expect(a).toEqual(c); // passes
To check if something is an array, you can use the Array.isArray helper from JavaScript.
const a = [1, 2];
expect(Array.isArray(a)).toBeTrue(); // passes
expect(a).toEqual([1, 2]); // passes

Related

How to mock an imported constant with Jasmine?

A component is meant to behave differently based on a external variable, which is used as a kind of configuration. I would like to test all the possible behaviors, but I don't get how to mock a constant variable.
I tried to use spyOnProperty as in the code below, but an error occurs, stating that the variable is not declared configurable.
// constants.js
export const DEFAULT_STATUS = 'test';
// component.spec.js
import * as constants from './constants';
// here other stuff and component init
it('should change default class based on a constant', () => {
const tmpDefaultStatus = 'test1';
spyOnProperty(constants, 'DEFAULT_STATUS', 'get').and.returnValue(tmpDefaultStatus);
expect(component.className).toBe(tmpDefaultStatus)
});
Then this error is thrown:
Error: : DEFAULT_STATUS is not declared configurable.
Is it still possible to mock that variable, without changing constant.js content?
I don't think there is. I would do:
it('should change default class based on a constant', () => {
const oldState = constants.DEFAULT_STATUS;
const tmpDefaultStatus = 'test1';
constants.DEFAULT_STATUS = tmpDefaultStatus;
expect(component.className).toBe(tmpDefaultStatus);
constants.DEFAULT_STATUS = oldState;
});
I am not sure if that test will pass or not but the idea is to change the value and take it back to its original for each test.

jest.fn() v/s jest.mock()?

For mocking uuidv4, I am using this :
import { v4 as uuidv4 } from "uuid";
jest.mock("uuid");
uuidv4.mockReturnValue("uuid123");
And for mocking window.confirm, I am using this:
window.confirm = jest.fn().mockImplementation(() => true);
These both are working all right.
But when i try doing this i.e
const uuidv4 = jest.fn.mockImplementation(() => "uuid123");
I get this error
TypeError: jest.fn.mockImplementation is not a function
I am confused between jest.fn() and jest.mock().
Can someone please elaborate on which one to use and when to use, with suitable example?
Just a quick explanation for you:
jest.mock is to mock a certain module. Once you write jest.mock('uuid') then it means all exported things would be turned to a jest.Mock type, that's why you can mock v4 method: v4.mockReturnValue('yourV4Id');
jest.mock('aModule');
import {aMember} from "aModule";
// is now a jest mock type <=> jest.fn()
aMember.mockReturnValue('a value');
jest.fn is a function which returns a jest.Mock type which can be considered as an function to create whatever you want:
const aMock = jest.fn().mockReturnValue(1) // <=> const aMock = () => 1;
// The difference is jest mock type can be used to assert then. Most of cases is to check
// whether it gets called or not

Moq Verify not matching on invocation

Before starting, I have used Moq to mock things in unit tests for years. This should be a simple mock verify, but for whatever reason moq is not matching the invocation on the Mock when it occurs. I've manually tested, it is hit. I've debugged the test and compared actual vs. expected values (they match), I've scoured SO and its multitudes of people doing blatantly wrong things and I cannot figure out why this isn't working. Help appreciated.
The unit test is a very simple test of checking if BulkInsert is called at the end of a void returning function. Sample code:
Code:
public interface IDependencyService
{
void BulkInsert(IList<T> items);
}
public class MyServiceClass
{
private readonly IDependencyService _service;
/* ctor and all that jazz */
public void Run()
{
/* do things to the data */
_service.BulkInsert(items); // where items is an IList<T>
}
}
Test:
public class ServiceTests
{
[Fact]
public void ServiceRun_Calls_DependencyBulkInsert()
{
var dependencyMock = new Mock<IDependencyService>();
List<T> expected = /* somehow build expected values */
dependencyMock
.Setup(mock => mock.BulkInsert(It.IsAny<IList<T>>()));
var sut = new MyServiceClass(dependencyMock.Object);
sut.Run();
dependencyMock.Verify(mock => mock.BulkInsert(expected), Times.Once());
}
}
Error message:
Expected invocation on the mock once, but was 0 times: mock => mock.BulkInsert([ThresholdCheck])
Performed invocations:
Mock<IThresholdCheckHandler:1> (mock):
IThresholdCheckHandler.GetQueuedChecks()
IThresholdCheckHandler.BulkInsert([ThresholdCheck])
If I change expected to It.IsAny<T>() in the Verify call, test passes. This leads me to believe that maybe somehow the objects passed from expected are somehow different from the objects generated when running the program. However as stated I've went through with the debugger and manually compared every value in the actual list to the expected list of values in the test and they are exactly the same.
This then leads me to believe that I'm just a stupid bipedal monkey clicking at a keyboard and that the problem is right in front of me and I'm just not seeing it. Any help or set of eyes is appreciated.
As per NKosi's comment, Verify operates via. reference when using reference types. I was confused as I'd used Verify in the past for simple things like ints and strings but was unaware of that quirk. One would assume with Verify that it would check the equivalency of actual vs. expected, but no.
Regardless then, as per Quercus's comment I adjusted my test to this in order to continue with my day:
public class ServiceTests
{
[Fact]
public void ServiceRun_Calls_DependencyBulkInsert()
{
var dependencyMock = new Mock<IDependencyService>();
List<T> actual = new List<T>();
List<T> expected = /* somehow build expected values */
dependencyMock
.Setup(mock => mock.BulkInsert(It.IsAny<IList<T>>()))
.Callback<List<T>>(l => actual = l);
var sut = new MyServiceClass(dependencyMock.Object);
sut.Run();
actual.Should().BeEquivalentTo(expected);
}
}
and this solution works for me. thanks to you both for helping me realize my mistake.

Mocking a method which is called using an arrow function as a parameter

How can I use the Sinon package to stub/mock a method call where one of the parameters I have to mock is called using an arrow function? eg
let objWithMethod = { method : function(x) {}; };
function SUT() {
// use case
let x = 'some value';
let y = { anotherMethod : function(func) {}; };
// I want to test that `y.anotherMethod()` is called with
// `(x) => objWithMethod.method(x)` as the argument
y.anotherMethod((x) => objWithMethod.method(x));
}
let mockObj = sinon.mock(objWithMethod);
// Both of these fail with a "never called" error
mockObj.expects('method').once().withArgs(objWithMethod.method.bind(this, x));
mockObj.expects('method').once().withArgs((x) => objWithMethod.method(x));
SUT();
mockObj.verify();
I couldn't find anything in the sinon docs nor after a few attempts at a google search.
Loose matches you're trying to do can be done with matchers, to compare against any function it should be
mockObj.expects('method').withArgs(sinon.match.func)
And it will fail, because objWithMethod.method isn't called at all.
This
// I want to test that y.anotherMethod() is called with
// (x) => objWithMethod.method(x) as the argument
cannot be done, because the code wasn't written with tests in mind. JS can't reflect local variables, and SUT function is a blackbox.
In order to be reachable for tests and get 100% coverage, each and every variable and closure should be exposed to the outer world.

How test SqlParameter for equality

Using NUnit and NMock2 I was not able to compare what I thought were the same SqlParameters:
SqlParameter param1 = new SqlParameter("#Id", 1);
SqlParameter param2 = new SqlParameter("#Id", 1);
Assert.IsTrue(param1.Equals(param2)); // This failed
I stumbled across this problem, when trying to test an execution of a method using NMock2
[Test]
public void UpdateComments()
{
const int arbitraryId = 1;
Comment comment = new Comment();
SqlParameter idParam = new SqlParameter("#ChangeId", arbitraryId);
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", idParam);
changeDao.UpdateComment(arbitraryId, comment);
mocks.VerifyAllExpectationsHaveBeenMet();
}
I received this error:
NMock2.Internal.ExpectationException: unexpected invocation of sqlDao.ExecuteNonQuery("usp_Update_Comment", )
Expected:
1 time: sqlDao.ExecuteNonQuery(equal to "usp_Update_Comment", equal to <#ChangeId>) [called 0 times]
Questions:
How do you test with NMock2 when you
expected Parameter is SqlParameter?
How do you compare equality of two SqlParameters?
Because .Equals() is using the default implementation of Equals as far as I know (which means that a SqlParameter will only "equal" another SqlParameter if they are the same object), you will need to directly interrogate the properties of the parameter to ensure the correct data is being passed.
The Has.Property call within .With allows you to check the properties of a parameter without requiring that a parameter equals some other value. Try the following:
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", Has.Property("ParameterName").EqualTo("#Id") &
Has.Property("Value").EqualTo(1));