我是Jasmine的新手,刚刚开始使用它。我有一个库js文件,其中包含许多与任何对象无关的函数(即全局)。我该如何监视这些功能?
我尝试使用窗口/文档作为对象,但即使调用该函数,间谍也无法工作。我也尝试将它包装在假物体中,如下所示:
var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");
并使用
进行测试expect(fakeElement.fakeMethod).toHaveBeenCalled();
这不起作用,因为间谍不起作用
答案 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()