How do I unit test this class? - javascript

Suppose I need to add unit tests for the following class from legacy code (that has no unit test for now). It is just a simple map or dictionary.
function Map(...) { ... }
Map.prototype.put = function (key, value) {
// associate the value with the key in this map
}
Map.prototype.get = function (key) {
// return the value to which the specified key is mapped, or undefined
// if this map contains no mapping for the key
}
Map.prototype.equals = function (obj) { ... }
// ... and more bound functions
It seems there is no way to test only one function at a time. You cannot test get() without calling put(), for example. How do I unit test this?

If there is a heavy dependancy between the methods you could stub or mock out all the other methods.. Have a look at jsMock for this.

Each method has a contract, explicit or implicit. Map.put() takes some kind of input and mutates something internal or external to Map. In order to test that function, your test needs access to what is mutated. If it is internal and not exposed externally, your test must either exist inside the Map class, the state must be exposed, or the mutateable state structure must be injected into the class in a way that external access remains possible:
ie:
/*Definition*/
function MockRepository() { /*implementation of the repository*/ }
function Map(repository) { /* store the repository */ }
Map.prototype.put = function() { /* mutate stuff in the repository */ }
/*Instantiation/Test*/
var mockRepository = new MockRepository(); /*mock repository has public methods to check state*/
var myMap = new Map(mockRepository);
myMap.put(/*whatever test input*/);
/* here use the mock repository to check that mutation of state occurred as expected based on ititial state of respository and input */

if you are working with data base, for the "get" method you can create DbScripts with inserts in your data base and then get those inserted items.
then you have to create DbScripts for deleting those added items.
for the "put" test you'll have to call the get method to check if it was inserted.
you just have to configure this in your test base class.
[TestFixtureSetUp]
public virtual void InitializeTestData()
{
TestConfiguration.ExecuteSqlFilesInFolder(this.DefaultScriptDirectory + "\\SetUp");
if (!string.IsNullOrEmpty(this.TestFixtureSpecificScriptDirectory))
{
TestConfiguration.ExecuteSqlFilesInFolder(this.TestFixtureSpecificScriptDirectory + "\\SetUp");
}
}
[TestFixtureTearDown]
public virtual void FinalizeTestData()
{
if (!string.IsNullOrEmpty(this.TestFixtureSpecificScriptDirectory))
{
TestConfiguration.ExecuteSqlFilesInFolder(this.TestFixtureSpecificScriptDirectory + "\\TearDown");
}
TestConfiguration.ExecuteSqlFilesInFolder(this.DefaultScriptDirectory + "\\TearDown");
}

Related

Is it possible to identify a role after building a Vuejs project?

I have a file that exports some functions in a Vuejs project, and I need to use them also in an external environment .. inComponent I know which function I should use by identifying by name and comparing with a .JSON file this works cool in the environment of development but when I build the project the functions are renamed as in the image:
Is there any other reference in these functions where I can identify them other than by name? any reference in memory I don't know? Thank you!
You can define a unique value in the body of each function and then when you have a reference to one of the functions in your list you can call the toString() method of the function reference to get the source code of the function - and then check whether the desired unique value is present in the code.
Something like this:
const myFunc1 = function (...)
{
const uniqueIdent = 'zvjbesvfexrxe3cg4g3ewumkaj2hrz9m';
.....
}
const myFunc2 = function (...)
{
const uniqueIdent = 'y4wxfjedrr3mh6k5ju2gcff6wxafjcz5';
.....
}
// make the list of functions globally available
window.myFuncList = { myFunc1, myFunc2 };
// try to find the uglyfied name of Func2
var key;
var realNameFunc2;
for (key in window.myFuncList)
{
if (window.myFuncList[key].toString().indexOf('y4wxfjedrr3mh6k5ju2gcff6wxafjcz5') !== -1)
{
realNameFunc2 = key;
break;
}
}
// you can now invoke your function as realNameFunc2(...)

Filter properties from ES6 class

I have a Dto that I want to enable the service layer to filter:
The method selectFields takes an array of field names that should be returned, the other properties will be removed.
What is a short way to enumerate the properties on the class so I can loop through them and set the filtered ones to null?
In the BaseDto I take care of cleaning falsy values (well I need the same function here too as a matter of fact).
class UserServiceDto extends BaseDto {
constructor(userDto) {
super();
this.fbUserId = userDto.fbUserId;
this.fbFirstName = userDto.fbFirstName;
this.fbLastName = userDto.fbLastName;
this.gender = userDto.gender;
this.birthdate = userDto.birthdate;
this.aboutMe = userDto.aboutMe;
this.deviceToken = userDto.deviceToken;
this.refreshToken = userDto.refreshToken;
this.updatedAt = userDto.updatedAt;
this.createdAt = userDto.createdAt;
}
selectFields(fields) {
// --> what's your take?
}
toJson() {
return super.toJson();
}
}
Edit:
The service layer receives a dto from repository layer including all database fields. The ServiceLayerDto aims at filtering out fields that are not required by the web api (or should not be exposed as a security measure e.g. PK field, isDeleted, etc). So the result would I'm looking at the end of a service method for would look something like:
return new UserServiceDto(userDto)
.selectFields('fbUserId', 'fbFirstName', 'fbLastName', 'birthdate', 'aboutMe', 'updatedAt', 'createdAt')
.toJson();
The return value would be a plain json object that the web layer (controller) sends back to the http client.
If you are ok with spread operator, you may try following approach:
class UserServiceDto {
constructor() {
this.a = 1;
this.b = 2;
this.c = 3;
}
selectFields(...fields) {
const result = {};
fields.forEach(key => result[key] = this[key]);
return result;
}
}
new UserServiceDto().selectFields('a', 'c'); // {a: 1, c: 3}
Looking to super.toJson() call, I think that it would not work due to the result of my selectFields() call would not be an instance of UserServiceDto class. There are some possible ways from this point I see:
instantiate new UserServiceDto object inside selectFields() body, remove all fields that not listed in the ...fields array (javascript delete is okey) and return it;
play with UserServiceDto constructor params to save positive logic on selectFields(), and pass to constructor only that props that need to be set up; in this case instantiating a temporary object will not require properties removing;
change the signature of toJson method, or better add a new signature, which would allow to pass fields array and then put current selectFields logic inside toJson method (and remove selectFields method at all): new UserServiceDto().toJson('a', 'c')...
Purely for info, I ultimately changed my app architecture.
The repository returns a Dto to the service layer (dto being mapped directly from the sql queries).
The service builds a static View based on the Dto and returns it to the web layer (represented by a plain json object).
In my directory structure, I have:
- service
-- views
--- index.js
--- UserInfo.js
The view is a simple filter. E.g. UserInfoView:
exports.build = ({ fbUserId, fbFirstName, fbLastName, gender, birthdate, aboutMe, updatedAt, createdAt }) => {
return {
fbUserId,
fbFirstName,
fbLastName,
gender,
birthdate,
aboutMe,
updatedAt,
createdAt,
};
};
Using the view, e.g. UserInfoView in the service looks like this:
const Views = require('../service/views');
exports.findActiveByUserId = async (pUserId) => {
const userDto = await UserRepository.findActiveByUserId(pUserId);
if (!userDto) {
throw new ServiceError(Err.USER_NOT_FOUND, Err.USER_NOT_FOUND_MSG);
}
return Views.UserInfo.build(userDto.toJson());
};
I think that this is much more descriptive compared to my initial take on the problem. Also, it keeps the data objects plain (no additional methods required).
It is unfortunate that I can't require receiving an type (View) in the web layer, I might be able to solve that problem with Typescript later on.

Javascript - Call parent function and extend method

This is probably a stupid question, but is there way in Javascript (ES5 preferred) to "extend" a class function similar to how i can i extend a parent' function in PHP ?
Basicly, i have this class hierarchy from System -> Weapon -> Dual and i would like Dual to use the code from System.setState() and then do some more stuff.
Note i use pre ES6 syntax for my hierarchy.
function System(system){
this.setState = function(){
//do stuff
}
}
function Weapon(system){
System.call(this, system);
}
Weapon.prototype = Object.create(System.prototype);
function Dual(system){
Weapon.call(this, system);
this.setState = function(){ // this is the problem
System.prototype.setState(); // error - not defined
//Weapon.protoype.setState() doesnt work either
//do more stuff
}
}
Dual.prototype = Object.create(Weapon.prototype);
Because setState is an instance property of System it does not exist on System.proptotype so you can't call it using System.prototype.setState.call. If you want to call it in this case, just create an object from System like so
function Dual(system){
Weapon.call(this, system);
var parent = new System(system);
this.setState = function() {
parent.setState(); // done
}
}
Instance properties are duplicated on each individual object ( they don't share). Whereas, prototype properties will be shared among children( they are not duplicated on child classes). To make all System 's subclasses share setState function, add it to System 's prototype
function System (arg) { ... }
System.prototype.setState = function () {...}
Now in your child classes, you can do
function Dual(system){
Weapon.call(this, system);
this.setState = function() {
System.prototype.setState.call(this); // done
}
}
First, you should set your instance methods on the prototype:
System.prototype.setState = function() {
// your stuff
}
This will improve performance and allow you to inherit the method without constructing a System instance.
Then, you just need to call System's version of setState on the right object (the instance of Dual) instead of calling it on System.prototype:
Dual.prototype = Object.create(Weapon.prototype, {
'setState': { value: function(){
System.prototype.setState.call(this) // fixed
// other stuff
}}
})

$onChanges doesn't get called when pushing an item to an array

Im using Angular 1.5.3 with typescript.
I have a outer and a inner component where the outercomponents holds an array named arrayValue which I pass to the innercomponent via <binding:
class InnerComponent {
controller: Function = InnerController;
bindings: any = {
arrayValue : "<"
};
...
}
The InnerController uses the $onChanges method to track any changes from one-way bindings (e. g. arrayValue):
public $onChanges(changes: any){
this.onChangesCalledCounter++;
console.log(changes);
}
If I now change the arrayValue within the outer component using:
public switchArrayValue(): void {
if(this.arrayValue === this.fruits){
this.arrayValue = this.vegetables;
} else {
this.arrayValue = this.fruits;
}
}
The $onChanges within the innercomponent gets called. However, If I change the switchArrayValue method to perform a push instead of a reassignment of the array, the $onChanges method won't get called:
public switchArrayValue(): void {
this.arrayValue.push("hello, world!");
}
Can anyone tell me why the push don't trigger the $onChanges and maybe show a workaround for that?
Here is a plnkr (that I forked).

How to dynamically append a record into an Array in flex?

I have an mxml view in flex, and I need to dynamically add data to a DataGrid component.
This is where the DataGrid is initialized:
<mx:DataGrid id="myGrid" width="100%"
dataProvider="{initDG}" >
<mx:columns>
<mx:DataGridColumn dataField="Identifier" />
<mx:DataGridColumn dataField="Name" />
</mx:columns>
</mx:DataGrid>
This is the script part:
private var DGArray:Array = new Array;
[Bindable]
public var initDG:ArrayCollection;
private function onCreation():void{
initData();
}
public function initData():void {
initDG=new ArrayCollection(DGArray);
}
private function onShow():void{
for (var child:Object in children) {
var details:Array = null;
if (child instanceof String) {
var test:String = children[child].toString();
details = test.split(",");
}
//Here I need to make an object like this one:
// record = {Identifier: details[0] , Name: details[1]};
this.DGArray.push(the record created);
}
}
I did this method because it's working if DGArray was a static Array:
private var DGArray:Array = [
{Identifier:'001', Name:'Slanted and Enchanted'},
{Identifier:'002', NAme:'Brighten the Corners'}];
Can anyone tell me how to create the record and add it to DGArray?
Thanks:)
In short
Add or remove items through the ArrayCollection instance instead of through the Array instance.
And here's why
ArrayCollection - as its name suggests - is in fact nothing but a wrapper around Array, adding some functionality to it that comes in handy when working with the Flex framework.
So when you do
initDG.addItem(theNewItem);
that new item will automatically also be added to the underlying Array.
Additionally this function will also dispatch a CollectionEvent, which will notify the DataGrid that the data in its dataProvider has changed and it should be redrawn to reflect those changes.
If on the other hand you do
DGArray.push(theNewItem);
like you did, you directly alter the underlying Array. This doesn't really break anything; you'll still be able to acces the new item through e.g. ArrayCollection.getItemAt() as well, but the DataGrid was never notified of the change, hence it didn't redraw and keeps displaying the old data.

Categories