bearcatjs / bearcat

powered by enhanced javaScript objects
http://bearcatjs.org/
Other
591 stars 110 forks source link

All testcase based on bearcat fail after updating from 0.2.37 to 0.3.15 #131

Closed zj8487 closed 9 years ago

zj8487 commented 9 years ago

_All testcases say an error:_

TypeError: Cannot read property 'start' of undefined

_error is throw from bearcat.start() in every testcase file_

    before(function(done) {
        bearcat.start(function() {
            done();
        });
    });

_I noticed that the Bearcat.createApp has been changed_

Bearcat.createApp = function(configLocations, opts) {
    if (this.state >= STATE_INITED) {
        return;
    }

_I tried change the code as follow but it fails too._

Bearcat.createApp = function(configLocations, opts) {
    if (this.state >= STATE_INITED) {
        return Bearcat;
    }

_you can use bearcat-dao to test after updating the bearcat_

fantasyni commented 9 years ago

哪里的测试用例?

zj8487 commented 9 years ago

@fantasyni 我自己项目的测试用例。 你可以用bearcat-dao测试。 我升级前都是ok的。升级后全部不过。

fantasyni commented 9 years ago

这里 bearcat 哪里来的

 before(function(done) {
        bearcat.start(function() {
            done();
        });
    });
zj8487 commented 9 years ago

每个测试文件的初始化部分

"use strict";

var path = require('path');
var should = require('should');
var assert = require("assert");
var Bearcat = require('bearcat');

describe('xxx Test', function(){
    var contextPath = require.resolve('../../../contextTest.json');
    var paths = [contextPath];
    var bearcat = Bearcat.createApp(paths);

    before(function(done) {
        bearcat.start(function() {
            done();
        });
    });
fantasyni commented 9 years ago

因为 bearcat 文件 是 require 进来的,是单例的,这个就是共享的,在同一个进程里面
所以每次在一个文件用完之后要 bearcat.stop() 一下才行
或者在 bearcat.createApp 之前执行下 bearcat.stop() 清理一下 require('bearcat') 的状态

fantasyni commented 9 years ago
Bearcat.createApp = function(configLocations, opts) {
    if (this.state >= STATE_INITED) {
        return Bearcat;
    }

改成这样子报错还是一样吗?

zj8487 commented 9 years ago

错误不一样了。报错:所以getBean() 出来的对象都是null

fantasyni commented 9 years ago

我现在的项目都是有一个 after 的
这个其实就是 require 在单元测试里的坑

after(function(done) {
        bearcat.stop();
        done();
    });
zj8487 commented 9 years ago

我改了试一试。 但是建议还是和以前保持一致,这样的话新手面对的坑少些。也更方便

fantasyni commented 9 years ago

恩,我大概知道了,我等下发个版本

fantasyni commented 9 years ago
Bearcat.createApp = function(configLocations, opts) {
    if (this.state >= STATE_INITED) {
        Bearcat.stop();
    }
}

改成这样子试试 把 bearcat.js 里面

zj8487 commented 9 years ago

好的

zj8487 commented 9 years ago

改成Bearcat.stop(); 后还是报错:getBean() 出来的对象都是null

fantasyni commented 9 years ago

晕,有什么日志输出吗?

zj8487 commented 9 years ago

[2015-02-13 19:28:00.289] [ERROR] bearcat - [BeanFactory] BeanFactory beanDefinition null for

fantasyni commented 9 years ago

这个不科学啊,bearcat-dao我试了已经可以了

fantasyni commented 9 years ago
logger.info('Bearcat startup in %s with %s ms', env, Date.now() - self.startTime);

这句话输出了吗

zj8487 commented 9 years ago

bearcat-dao 使用了$xx这种注入吗?

zj8487 commented 9 years ago

这是第一个错误的stack

      at null.aaa (/home/xxxxx/app/util/xxx.js:26:39)
      at Object.MetaUtil.resolveFuncAnnotation (/home/xxxxx/node_modules/bearcat/lib/util/metaUtil.js:89:24)
      at MetaLoader.loadFile (/home/xxxxx/node_modules/bearcat/lib/resource/metaLoader.js:87:19)
      at MetaLoader.loadPath (/home/xxxxx/node_modules/bearcat/lib/resource/metaLoader.js:137:12)
      at MetaLoader.load (/home/xxxxx/node_modules/bearcat/lib/resource/metaLoader.js:51:7)
      at ConfigLoader.getResources (/home/xxxxx/node_modules/bearcat/lib/resource/configLoader.js:61:14)
      at ResourceLoader.load (/home/xxxxx/node_modules/bearcat/lib/resource/resourceLoader.js:61:43)
      at ApplicationContext.getResource (/home/xxxxx/node_modules/bearcat/lib/context/applicationContext.js:153:29)
      at ApplicationContext.refreshBeanFactory (/home/xxxxx/node_modules/bearcat/lib/context/applicationContext.js:332:39)
      at ApplicationContext.refresh (/home/xxxxx/node_modules/bearcat/lib/context/applicationContext.js:201:7)
      at EventEmitter.Bearcat.start (/home/xxxxx/node_modules/bearcat/lib/bearcat.js:137:26)
      at Context.<anonymous> (/home/xxxxx/test/qqq/xxx/xxxxManagerTest.js:16:17)
      at Hook.Runnable.run (/home/xxxxx/node_modules/mocha/lib/runnable.js:218:15)
      at Hook.Runnable.run (/home/xxxxx/node_modules/bluebird-mocha-generators/index.js:12:14)
      at next (/home/xxxxx/node_modules/mocha/lib/runner.js:259:10)
      at Immediate._onImmediate (/home/xxxxx/node_modules/mocha/lib/runner.js:276:5)
      at processImmediate [as _immediateCallback] (timers.js:321:17)
fantasyni commented 9 years ago

ok thx 有堆栈我再仔细看看

fantasyni commented 9 years ago

你那个bean咋写的能示例贴一下吗?混淆一下变量名

zj8487 commented 9 years ago
"use strict";

var Promise = require("bluebird");

var XXXXUtil = function() {
    this.$id = "xxxxUtil";
    this.$requireUtil = null;
    this._publicXX = null;
}

function defineGetter(key, getFunction) {
    Object.defineProperty(XXXXUtil.prototype, key, {
        configurable: false,
        enumerable: true,
        get: getFunction
    });
};

defineGetter("publicXX", function () {
    if (this._publicXX) return this._publicXX;

    this._publicXX = this.$requireUtil.ip.address("public");  // this.$requireUtil is null
    if (this._publicXX == "127.0.0.1") {
        this._publicXX = this.$requireUtil.ip.address("private");
    }

    return this._publicXX;
});

module.exports = XXXXUtil
fantasyni commented 9 years ago

你试试在 bearcat/lib/util/metaUtil.js 里面的89行后面加入看看

if (Utils.checkFunction(value)) {
    continue;
}
    for (var funcKey in funcProps) {
        var value = funcProps[funcKey];
        if (Utils.checkFunction(value)) {
            continue;
        }

        if (MetaUtil.checkFuncAnnotation(funcKey)) {
            var key = funcKey.substr(1);
            if (MetaUtil.checkInMetaProps(funcKey)) {
                if (key === Constant.META_AOP && funcProps[funcKey] === true) {
                    meta[key] = this.resolvePrototypeAnnotation(func);
                } else {
                    meta[key] = funcProps[funcKey];
                }
            } else {
                if (!MetaUtil.checkInFuncArgs(funcKey, funcArgs)) {
                    if (MetaUtil.checkFuncPropsValue(funcKey)) {
                        props.push({
                            name: funcKey,
                            value: value
                        });
                    } else if (MetaUtil.checkFuncPropsType(funcKey)) {
                        props.push({
                            name: funcKey,
                            type: value
                        });
                    } else if (MetaUtil.checkFuncPropsNamespace(funcKey)) {
                        props.push({
                            name: funcKey,
                            ref: value
                        });
                    } else {
                        props.push({
                            name: funcKey,
                            ref: key
                        });
                    }
                }
            }
        } else if (MetaUtil.checkFuncPropsConfigValue(value)) {
            props.push({
                name: funcKey,
                value: value
            });
        }
    }
zj8487 commented 9 years ago

89行后面不对吧。是89行就出错了啊。 加了,错误一样,堆栈一样

fantasyni commented 9 years ago

恩,我自己也复现了,应该是你用了 defineProperty 导致的 取出元素来就执行了 get 方法,而这时其实 this.$xxx 还没好

zj8487 commented 9 years ago

如何解决呢?

fantasyni commented 9 years ago

你这个是修改了默认的 get set 方法,有点坑啊,之前的版本没问题,是因为之前bearcat是通过解析function构造函数做字符串解析的,现在是通过 new function 构造函数来拿到里面的 $xxx 属性,这样子一来你这种情况就会有这么个问题

zj8487 commented 9 years ago

那就是我这种写法不支持?

fantasyni commented 9 years ago

要支持只能

for (var funcKey in funcProps) {
     try{
          var value = funcProps[funcKey];
     }catch(e) {
     }  
}

这样子捕捉异常,但是这样一来又有性能损失

之所以改成 new 的方式,因为这样子可以更加灵活
可以支持这样的

var Car = function() {
    this.$id = "car";
    this["$engine"] = null; // use []
    var wheelName = "$wheel";
    this[wheelName] = null; // use variable
};

Car.prototype["$light"] = null; // use variable in prototype

Car.prototype.run = function() {
    this.$engine.run();
    this.$light.shine();
    this.$wheel.run();
    console.log('car run...');
}

module.exports = Car;
zj8487 commented 9 years ago

但是在对象上进行getter, setter也是很常见啊 还能有什么其他办法吗?

fantasyni commented 9 years ago

目前只能加个 createApp 参数,强制使用 第一种通过解析构造函数字符串的形式来做
我再想想其它办法,感谢提出

zj8487 commented 9 years ago

好的,多谢,辛苦了

zj8487 commented 9 years ago

你先看看其他办法吧,我先降级就是了。 不用添加临时处理办法

fantasyni commented 9 years ago

我找到了方法,能规避你这种情况,就是直接忽视 prototype 里面定义的属性

    for (var funcKey in funcProps) {
        if (!funcProps.hasOwnProperty(funcKey)) {
            continue;
        }
       }

那唯一的漏洞就是 definePropery 到 this ,貌似没有人这么干吧,那样写法一般是

var a = {}
Object.defineProperty(a, 'b', {});
fantasyni commented 9 years ago

试试 bearcat@0.3.17 版本哈

zj8487 commented 9 years ago

define 到this的为什么不能忽略?

zj8487 commented 9 years ago

不好消息,0.3.17有两个case跑不过,是关于collections这个库的。0.2.x可以。 不知道是bearcat修改的影响还是collections的bug

zj8487 commented 9 years ago

@fantasyni 这样改有问题。 这样改了后我如下代码不工作了,这个应该和库没关系。

"use strict";

var Shim = require("collections/shim");
var array = require("collections/shim-array");
var util = require('util');

var Type = function(value, name) {
    this.value = Number(value);
    this.name = String(name);
};

Type.prototype.valueOf = function() {
    return this.value;
};

Type.prototype.toString = function() {
    return util.format('[%s|%d]', this.name, this.value);
};

var testObject = {
    "aa": new Type(0, "aa"),
    "bb": new Type(1, "bb"),
    "cc": new Type(2, "cc"),
    "dd": new Type(3, "dd"),
    "ee": new Type(4, "ee"),
    "ff": new Type(5, "ff"),
    "gg": new Type(6, "gg"),
    "hh": new Type(7, "hh"),
    "ii": new Type(8, "ii"),
    "jj": new Type(9, "jj"),
    "kk": new Type(10, "kk"),
};

var GGGGG = function() {
    this.$id = "ggggg";

    this.FUCK = testObject;
    this.FUCK.sortedLists = Object.values(testObject).sort(Object.compare);
    // 上面这行会报错。之前版本没问题。把这行移出去到外面也不报错。
};

module.exports = GGGGG;

相关库 https://github.com/montagejs/collections

fantasyni commented 9 years ago
fantasyni commented 9 years ago

找到原因了,是因为

Object.values(testObject).sort(Object.compare);

会把 testObject 对象给改变了

一般在构造函数里面是不做初始化逻辑的,如果有这个需求,可以放在 bearcat 提供的 init 方法里面,也是一样的效果,构造函数就是用来定义属性、依赖关系、配置信息

我更新个版本,可以强制指定使用解析构造函数字符串的形式吧

fantasyni commented 9 years ago

这样子的写法,new 多次就会复现一样的错误
一个文件内的全局变量很坑的,尽量避免

"use strict";

var Shim = require("collections/shim");
var array = require("collections/shim-array");
var util = require('util');

var Type = function(value, name) {
    this.value = Number(value);
    this.name = String(name);
};

Type.prototype.valueOf = function() {
    return this.value;
};

Type.prototype.toString = function() {
    return util.format('[%s|%d]', this.name, this.value);
};

var testObject = {
    "aa": new Type(0, "aa"),
    "bb": new Type(1, "bb"),
    "cc": new Type(2, "cc"),
    "dd": new Type(3, "dd"),
    "ee": new Type(4, "ee"),
    "ff": new Type(5, "ff"),
    "gg": new Type(6, "gg"),
    "hh": new Type(7, "hh"),
    "ii": new Type(8, "ii"),
    "jj": new Type(9, "jj"),
    "kk": new Type(10, "kk"),
};

var GGGGG = function() {
    this.$id = "ggggg";

    this.FUCK = testObject;
    this.FUCK.sortedLists = Object.values(testObject).sort(Object.compare);
    // 上面这行会报错。之前版本没问题。把这行移出去到外面也不报错。
};

module.exports = GGGGG;

new GGGGG();
new GGGGG();
zj8487 commented 9 years ago

ok, 我改改,你打算怎么做?

zj8487 commented 9 years ago

建议在bearcat使用说明中或,强行限制

一般在构造函数里面是不做初始化逻辑的
zj8487 commented 9 years ago

那上面的Type类型定义有问题没有?

一个文件内的全局变量很坑的,尽量避免
fantasyni commented 9 years ago

定义是可以的,但是实例对象(使用匿名对象)是有问题的,这样代码热更新也是不支持的,尽量写成无状态的吧,我等下发个版本

zj8487 commented 9 years ago

讨论个bearcat最佳实践问题: 你觉得Type定义是专门写个bean好还是就这样好?

zj8487 commented 9 years ago

建议做个限制,在构造函数中都不允许初始化,强制到init中。你看看是否可行?

fantasyni commented 9 years ago
zj8487 commented 9 years ago

0.4.x大概好久发布?

这个有无说明?

bearcat@0.3.18 已经自己做了处理,不 new 来获取依赖关系,但是要配置一下
fantasyni commented 9 years ago