Angularjs 与茉莉花一起使用上下文

Angularjs 与茉莉花一起使用上下文,angularjs,jasmine,angular-mock,Angularjs,Jasmine,Angular Mock,我想和jasmine一起使用上下文,这样我就可以组织我的模拟返回的内容。下面是一些伪代码来演示我要做的事情。我希望这两个期望都能实现: describe('a module', function(){ var whatTheFunctionReturns; beforeEach(function(){ module('anApp', function($provide){ $provide.value('aFactory', { aFunc

我想和jasmine一起使用上下文,这样我就可以组织我的模拟返回的内容。下面是一些伪代码来演示我要做的事情。我希望这两个期望都能实现:

describe('a module', function(){
    var whatTheFunctionReturns;
    beforeEach(function(){
        module('anApp', function($provide){
            $provide.value('aFactory', { aFunction: whatTheFunctionReturns })
        }
    });

    describe('when the function returns alpha', function(){
        whatTheFunctionReturns = 'alpha'

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'alpha' )
        }); 
    });
    describe('when the function returns beta', function(){
        whatTheFunctionReturns = 'beta'

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'beta' )
        }); 
    });
});
请仔细阅读以上内容。你明白我想做什么吗?代码

$provide.value('aFactory', { aFunction: whatTheFunctionReturns })
在beforeach块中写入一次,但变量

whatTheFunctionReturns
在两个描述块中更改,
当函数返回alpha时
当函数返回beta时

但是,它不起作用。下面是一些真实的代码,我试图测试一个控制器并模拟它所依赖的工厂:

describe('firstController', function(){
    var $rootScope, $scope, $controller
    var message = 'I am message default'

    beforeEach(function(){
        module('App',function($provide){
            $provide.value('ServiceData', { message: message})
        });
        inject(function(_$rootScope_,_$controller_){
            $rootScope = _$rootScope_
            $scope = $rootScope.$new()
            $controller = _$controller_
            $controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope })
        });
    });

    describe('when message 1', function(){
        beforeEach(function(){
            message = 'I am message one'
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '1' ) // using wrong data so I can see what data is being returned in the error message
        }); 
    });

    describe('when message 2', function(){
        beforeEach(function(){
            message = 'I am message two'
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '2' ) // using wrong data so I can see what data is being returned in the error message
        });
    });
});
以下是我收到的错误消息:

Firefox 34.0.0 (Ubuntu) firstController when message 1 should get data from a service FAILED
    Expected 'I am message default' to equal '1'.

Firefox 34.0.0 (Ubuntu) firstController when message 2 should get data from a service FAILED
    Expected 'I am message one' to equal '2'.
它工作了一半。变量正在更新,但仅在最后一个描述块中(
'when message 2'
以下是我希望返回的内容:

Firefox 34.0.0 (Ubuntu) firstController when message 1 should get data from a service FAILED
    Expected 'I am message one' to equal '1'.

Firefox 34.0.0 (Ubuntu) firstController when message 2 should get data from a service FAILED
    Expected 'I am message two' to equal '2'.

我怎样才能做到这一点?你明白我想用descripe块做什么吗?

你误解了Jasmine在执行每个测试之前是如何构建测试用例的

看看这个,然后执行它:

describe("Test", function(){
    console.info("Calling beforeEach() before describe()");
    beforeEach(function(){
        console.info("Running before()");
    });

    console.info("Calling describe() A");
    describe("describe A", function(){
        console.info("Calling it() A 0");

        it('should A 0', function(){
            console.info("Running it() A 1");
            expect("test to be").toBe("implemented");
        });

        console.info("Calling it() A 1");
        it('should A 1', function(){
            console.info("Running it() A 2");
            expect("test to be").toBe("implemented");
        });

        console.info("Calling it() A 2");
        it('should A 2', function(){
            console.info("Running it() A 3");
            expect("test to be").toBe("implemented");
        });
    });

});
在控制台中,您将观察到以下情况:

Calling beforeEach() before describe()
Calling describe() A
Calling it() A 0
Calling it() A 1
Calling it() A 2
Running before()
Running it() A 1
Running before()
Running it() A 2
Running before()
Running it() A 3
这是怎么回事

调用
descripe()
时,将执行您提供的回调函数中的代码。对其他
descripe()
s的后续调用将执行对的回调。对
it()
beforeach()
afterEach()
的每次调用都将在内部队列树中对传递的回调进行排队,before将前置到每个分支,after将追加到该分支。然后队列一个接一个地移动,Jasmine将为每个步骤执行存储的回调

当查看第一个代码时,这意味着执行函数返回的所有
赋值,然后执行每个
it()
(前面是
beforeach()


你应该做什么:

describe('a module', function(){
    var whatTheFunctionReturns;

    // pepare to run in beforeEach()
    function _beforeModule(){
        module('anApp', function($provide){
            $provide.value('aFactory', { aFunction: whatTheFunctionReturns })
        }
    }

    describe('when the function returns alpha', function(){
        beforeEach(function(){
           whatTheFunctionReturns = 'alpha';
           _beforeModule();
        });

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'alpha' )
        }); 
    });
    describe('when the function returns beta', function(){
        beforeEach(function(){
           whatTheFunctionReturns = 'beta';
           _beforeModule();
        });

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'beta' )
        }); 
    });
});

您必须将分配包装到
beforeach()
it()
块中。

您误解了Jasmine在执行每个测试之前是如何构建测试用例的

看看这个,然后执行它:

describe("Test", function(){
    console.info("Calling beforeEach() before describe()");
    beforeEach(function(){
        console.info("Running before()");
    });

    console.info("Calling describe() A");
    describe("describe A", function(){
        console.info("Calling it() A 0");

        it('should A 0', function(){
            console.info("Running it() A 1");
            expect("test to be").toBe("implemented");
        });

        console.info("Calling it() A 1");
        it('should A 1', function(){
            console.info("Running it() A 2");
            expect("test to be").toBe("implemented");
        });

        console.info("Calling it() A 2");
        it('should A 2', function(){
            console.info("Running it() A 3");
            expect("test to be").toBe("implemented");
        });
    });

});
在控制台中,您将观察到以下情况:

Calling beforeEach() before describe()
Calling describe() A
Calling it() A 0
Calling it() A 1
Calling it() A 2
Running before()
Running it() A 1
Running before()
Running it() A 2
Running before()
Running it() A 3
这是怎么回事

调用
descripe()
时,将执行您提供的回调函数中的代码。对其他
descripe()
s的后续调用将执行对的回调。对
it()
beforeach()
afterEach()
的每次调用都将在内部队列树中对传递的回调进行排队,before将前置到每个分支,after将追加到该分支。然后队列一个接一个地移动,Jasmine将为每个步骤执行存储的回调

当查看第一个代码时,这意味着执行函数返回的所有
赋值,然后执行每个
it()
(前面是
beforeach()


你应该做什么:

describe('a module', function(){
    var whatTheFunctionReturns;

    // pepare to run in beforeEach()
    function _beforeModule(){
        module('anApp', function($provide){
            $provide.value('aFactory', { aFunction: whatTheFunctionReturns })
        }
    }

    describe('when the function returns alpha', function(){
        beforeEach(function(){
           whatTheFunctionReturns = 'alpha';
           _beforeModule();
        });

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'alpha' )
        }); 
    });
    describe('when the function returns beta', function(){
        beforeEach(function(){
           whatTheFunctionReturns = 'beta';
           _beforeModule();
        });

        it('should get data from a service', function(){
            expect(aFactory.aFunction).toEqual( 'beta' )
        }); 
    });
});

您必须将工作分配包装到
beforeach()
it()
块中。

不幸的是,Jasmine在its中没有概念,这意味着在技术上不可能使用动态范围重用您的期望主体,并根据不同的值测试其行为。为了使Jasmine具有这种级别的可重用性,您所做的一切都是一种变通方法,而不是由创建者设计的

在您的演示代码中,当您在第一个beforeach中调用$controller函数时,无论您做什么,它都将使用默认值解析其所有依赖项

$controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope })

不幸的是,Jasmine在其中没有概念,这意味着在技术上不可能重用具有动态范围的期望主体,并根据不同的值测试其行为。为了使Jasmine具有这种级别的可重用性,您所做的一切都是一种变通方法,而不是由创建者设计的

在您的演示代码中,当您在第一个beforeach中调用$controller函数时,无论您做什么,它都将使用默认值解析其所有依赖项

$controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope })

我相信您遇到的问题是,用于在服务中分配“消息”的变量只是一个值对象。这是一个javascript问题,而不是jasmine问题

在将其分配给提供给服务的对象之后,修改它并不重要。例如:

var a = 1;
var b = a;
a = 2;
console.log(b); // will print out '1'
您想要的是能够在每次首次访问之后修改您提供给服务的对象,如下所示:

describe('firstController', function() {
    var $rootScope, $scope, $controller, serviceData 

    beforeEach(function(){
        serviceData = { message: 'I am message default' }
        module('App',function($provide){
            $provide.value('ServiceData', serviceData) // keep a reference to the object
        });
        inject(function(_$rootScope_,_$controller_){
            $rootScope = _$rootScope_
            $scope = $rootScope.$new()
            $controller = _$controller_
            $controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope })
        });
    });

    describe('when message 1', function(){
        beforeEach(function(){
            serviceData.message = 'I am message one' // that way, you modify the object that your 'ServiceData' provider holds.
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '1' )
        }); 
    });

    describe('when message 2', function(){
        beforeEach(function(){
            serviceData.message = 'I am message two'
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '2' ) 
        });
    });
});

免责声明:我不能100%确定$PROFECT.value的内部工作原理。如果上述方法不起作用,可能是因为$provide.value函数的对象是在内部克隆的。

我相信您遇到的问题是,用于在服务中分配“消息”的变量只是一个值对象。这是一个javascript问题,而不是jasmine问题

在将其分配给提供给服务的对象之后,修改它并不重要。例如:

var a = 1;
var b = a;
a = 2;
console.log(b); // will print out '1'
您想要的是能够在每次首次访问之后修改您提供给服务的对象,如下所示:

describe('firstController', function() {
    var $rootScope, $scope, $controller, serviceData 

    beforeEach(function(){
        serviceData = { message: 'I am message default' }
        module('App',function($provide){
            $provide.value('ServiceData', serviceData) // keep a reference to the object
        });
        inject(function(_$rootScope_,_$controller_){
            $rootScope = _$rootScope_
            $scope = $rootScope.$new()
            $controller = _$controller_
            $controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope })
        });
    });

    describe('when message 1', function(){
        beforeEach(function(){
            serviceData.message = 'I am message one' // that way, you modify the object that your 'ServiceData' provider holds.
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '1' )
        }); 
    });

    describe('when message 2', function(){
        beforeEach(function(){
            serviceData.message = 'I am message two'
        });
        it('should get data from a service', function(){
            expect($scope.serviceData.message).toEqual( '2' ) 
        });
    });
});

免责声明:我不能100%确定$PROFECT.value的内部工作原理。如果上述操作不起作用,可能是因为$PROFECT.value函数的对象是在内部克隆的。

为什么不在每次操作之前执行
(函数(ServiceData){ServiceData.message='I am message two'})
@Chandermani你也需要
inject()
你应该看看sinon的模仿/存根是正确的@james,我忘了那一部分。@james我已经看了sinon一小段……这允许我使用上下文吗?为什么不在每次(函数(ServiceData){ServiceData.message='i am message two')之前做
;
@Chandermani你也需要
inject()
你应该看看sinon的模仿/存根是正确的@james,i