使用Jasmine监视没有对象的函数

时间:2012-03-01 03:17:37

标签: javascript unit-testing jasmine

我是Jasmine的新手,刚刚开始使用它。我有一个库js文件,其中包含许多与任何对象无关的函数(即全局)。我该如何监视这些功能?

我尝试使用窗口/文档作为对象,但即使调用该函数,间谍也无法工作。我也尝试将它包装在假物体中,如下所示:

var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");

并使用

进行测试
expect(fakeElement.fakeMethod).toHaveBeenCalled();

这不起作用,因为间谍不起作用

8 个答案:

答案 0 :(得分:143)

如果您要定义您的功能:

function test() {};

然后,这相当于:

window.test = function() {}  /* (in the browser) */

所以spyOn(window, 'test')应该有用。

如果不是,您还应该能够:

test = jasmine.createSpy();

如果这些都不起作用,那么您的设置还会发生其他事情。

我不认为你的fakeElement技术是有效的,因为幕后发生了什么。原始的globalMethod仍然指向相同的代码。间谍做的是代理它,但仅限于对象的上下文中。如果你可以让你的测试代码通过fakeElement调用它可以工作,但是你可以放弃全局fns。

答案 1 :(得分:48)

TypeScript用户:

我知道OP询问了javascript,但是对于任何想要窥探导入功能的TypeScript用户来说,这就是你可以做的事情。

在测试文件中,转换函数的导入:

import {foo} from '../foo_functions';

x = foo(y);

对此:

import * as FooFunctions from '../foo_functions';

x = FooFunctions.foo(y);

然后你可以监视FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();

答案 2 :(得分:39)

我使用了2种替代品(用于茉莉花2)

这个不太明确,因为看起来这个函数实际上是假的。

test = createSpy().and.callFake(test); 

第二个更详细,更明确,更清洁":

test = createSpy('testSpy', test).and.callThrough();

- > jasmine source code查看第二个参数

答案 3 :(得分:8)

一种非常简单的方法:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');

答案 4 :(得分:1)

import * as saveAsFunctions from 'file-saver';
..........
....... 
let saveAs;
            beforeEach(() => {
                saveAs = jasmine.createSpy('saveAs');
            })
            it('should generate the excel on sample request details page', () => {
                spyOn(saveAsFunctions, 'saveAs').and.callFake(saveAs);
                expect(saveAsFunctions.saveAs).toHaveBeenCalled();
            })

这对我有用。

答案 5 :(得分:1)

我们通常采用的方法如下:

class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
String _email, _password, error = '';
bool _obscureText = true;
final Auth _auth = Auth();

_toggle(){
setState(() {
  _obscureText = !_obscureText;
});
}

_submit() async {
if(_formKey.currentState.validate()){
  _formKey.currentState.save();
  SharedPreferences prefs = await SharedPreferences.getInstance();
  prefs.setString('email', _email);
  dynamic result = await _auth.login(_email, _password);
  if(result == null){
    setState(() => error = 'There is no user record found. Please create account first!!!');
  } else {
    Navigator.pushNamed(context, HomePage.id);
  }
  print(_email);
  print(_password);
}
}

@override
Widget build(BuildContext context) {
return GestureDetector(
  onTap: (){
    FocusScopeNode currentFocus = FocusScope.of(context);

    if (!currentFocus.hasPrimaryFocus) {
      currentFocus.unfocus();
    }
  },
  child: Scaffold(
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Text(
            'Login',
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
          Form(
              key: _formKey,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 30.0, vertical: 10.0),
                    child: Padding(
                        padding: EdgeInsets.only(left: 5, right: 5, top: 5),
                      child: TextFormField(
                        decoration: InputDecoration(
                            labelText: 'Email',
                          border: InputBorder.none,
                          filled: true,
                          fillColor: Colors.white60,
                          focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide(color: Colors.blue,width: 2.0),
                            borderRadius: BorderRadius.circular(10.0)
                          ),
                          /*enabledBorder: UnderlineInputBorder(
                              borderRadius: BorderRadius.circular(10.0)
                          )*/
                        ),
                        validator: (input) => !input.contains('@')
                            ? 'Please enter valid email'
                            : null,
                        onSaved: (input) => _email = input,
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 30.0, vertical: 10.0),
                    child: Stack(
                      alignment: const Alignment(0, 0),
                      children: <Widget>[
                        TextFormField(
                          decoration: InputDecoration(
                              labelText: 'Password',
                            border: InputBorder.none,
                            filled: true,
                            fillColor: Colors.white60,
                            focusedBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.blue,width: 2.0),
                                borderRadius: BorderRadius.circular(10.0)
                            ),
                          ),
                          validator: (input) => input.length < 6
                              ? 'Must be at least 6 characters'
                              : null,
                          onSaved: (input) => _password = input,
                          obscureText: _obscureText,
                        ),
                        Positioned(
                          right: 15,
                          child: Container(
                            height: 30,
                            child: ElevatedButton(
                              onPressed: (){
                                _toggle();
                              },
                              child: Text(
                                  _obscureText ? 'Show' : 'Hide'
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  verticalSpaceMedium,
                  Container(
                    width: 200.0,
                    child: TextButton(
                      onPressed: _submit,
                      style: TextButton.styleFrom(
                        primary: Colors.white,
                        backgroundColor: Colors.blue,
                        elevation: 5,
                      ),
                      child: Text(
                        'Login',
                        style: TextStyle(color: Colors.white, fontSize: 16.0),
                      ),
                    ),
                  ),
                  verticalSpaceMedium,
                  Container(
                    width: 200.0,
                    child: TextButton(
                      style: TextButton.styleFrom(
                        primary: Colors.white,
                        backgroundColor: Colors.blue,
                        elevation: 5,
                      ),
                      onPressed: () => Navigator.pushNamed(context, SignupPage.id),
                      child: Text(
                        'Create Account',
                      ),
                    ),
                  ),
                  verticalSpaceMedium,
                  Text(error, style: TextStyle(color: Colors.red, fontSize: 14),)
                ],
              ),
          )
        ],
      ),
    ),
  ),
);

答案 6 :(得分:0)

我的答案与@FlavorScape略有不同,因为我在导入的模块中有一个(默认导出)功能,我做了以下事情:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');

答案 7 :(得分:-3)

必须可以在没有定义窗口的情况下使用。全球功能。尝试:

   var x = function() {}

   spyX = spyOn(x, 'call') //

   // something, that calls x
   expect(spyX).toBeCalled()