当前位置: 首页 > news >正文

前端测试框架 jasmine 的使用

  最近的项目在使用AngulaJs,对JS代码的测试问题就摆在了面前。通过对比我们选择了 Karma  + jasmine ,使用 Jasmine做单元测试 ,Karma 自动化完成,当然了如果使用 Karma  + jasmine 前提是必须安装 Nodejs。

安装好 Nodejs ,使用 npm 安装好必要的包,写了一个测试用例,测试通过,很好很强大。 没有 Nodejs 环境可以使用 Jasmine 做单元测试吗?当然可以,我们可以到 官网下一个示例看一看,比较简单。今天先讲一下如果直接使用

jasmine 做单元测试

   简单示例

   jasmine 示例下载地址  https://github.com/jasmine/jasmine/releases 选择最新版本下载下来示例代码结构如图

        

  lib 文件夹下面:  boot.js 启动文件  ,

            console.js 输出辅助文件,

              jasmine-html.js 测试页面 Dom 操作文件,

              jasmine.js jasmine核心文件

    spec 文件夹 :    PlayerSpec.js  单元测试文件

          SpecHelper.js    jasmine 断言扩展文件(自定义 Matcher)

    src 文件夹 ,下面是被测试的 js 文件。  SpecRunner.html 为测试结果页面。

  SpecRunner.html 代码,注意js文件加载顺序

   

+ View Code

    我们直接运行 SpecRunner.html  测试结果如下:

5个 specs,0个失败,全部通过。在 PlayerSpec.js 里添加一个Suite,看看报错是什么样的。

1

2

3

4

5

describe("error test",function() {

    it("Here the test does not pass",function() {

        expect(1).toBe(2);

    });

})

 

哈哈,测试未通过,看到没,这里显示了详细的错误信息。

   jasmine 语法详解

        首先了解几个概念: Suite 指一个测试集, describe方法标志着一个测试集。

            Spec 表示测试用例,jasmine中用方法it来开始 specs。

            一个 Suite可以包含多个 Spec,一个 spec 可以包含多个 expections 断言

  示例1

  

1

2

3

4

5

6

7

8

//测试集 开始于调用全局Jasmine函数describe,有两个参数:一个字符串和一个函数。

//该字符串是specs(测试用例)单元测试的名称或标题 - 通常是被测试的。 该函数是一个实现单元测试的代码块。

     

describe("A suite"function() {

  it("contains spec with an expectation"function() {

    expect(true).toBe(true);

  });

});

  示例2        包含多个断言

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

describe("A suite is just a function"function() {

  var a;

  it("and so is a spec"function() {

    a = true;

    expect(a).toBe(true);

  });

});

describe("The 'toBe' matcher compares with ==="function() {

  it("and has a positive case"function() {

    expect(true).toBe(true);

  });

  it("and can have a negative case"function() {

    expect(false).not.toBe(true);

  });

});

 示例3   常用语法,describe嵌套

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

describe("Included matchers:"function() {

  it("The 'toBe' matcher compares with ==="function() {

    var a = 12;

    var b = a;

    expect(a).toBe(b);

    expect(a).not.toBe(null);

  });

  describe("The 'toEqual' matcher"function() {

    it("works for simple literals and variables"function() {

      var a = 12;

      expect(a).toEqual(12);

    });

    it("should work for objects"function() {

      var foo = {

        a: 12,

        b: 34

      };

      var bar = {

        a: 12,

        b: 34

      };

      expect(foo).toEqual(bar);

    });

  });

  it("The 'toMatch' matcher is for regular expressions"function() {

    var message = "foo bar baz";

    expect(message).toMatch(/bar/);

    expect(message).toMatch("bar");

    expect(message).not.toMatch(/quux/);

  });

  it("The 'toBeDefined' matcher compares against `undefined`"function() {

    var a = {

      foo: "foo"

    };

    //已定义

    expect(a.foo).toBeDefined();

    expect(a.bar).not.toBeDefined();

  });

  it("The `toBeUndefined` matcher compares against `undefined`"function() {

    var a = {

      foo: "foo"

    };

    //未定义

    expect(a.foo).not.toBeUndefined();

    expect(a.bar).toBeUndefined();

  });

  it("The 'toBeNull' matcher compares against null"function() {

    var a = null;

    var foo = "foo";

    expect(null).toBeNull();

    expect(a).toBeNull();

    expect(foo).not.toBeNull();

  });

  it("The 'toBeTruthy' matcher is for boolean casting testing"function() {

    var a, foo = "foo";

     

    expect(foo).toBeTruthy();

    expect(a).not.toBeTruthy();

  });

  it("The 'toBeFalsy' matcher is for boolean casting testing"function() {

    var a, foo = "foo";

    expect(a).toBeFalsy();

    expect(foo).not.toBeFalsy();

  });

  describe("The 'toContain' matcher"function() {

    it("works for finding an item in an Array"function() {

      var a = ["foo""bar""baz"];

         

      //包含

      expect(a).toContain("bar");

      expect(a).not.toContain("quux");

    });

    it("also works for finding a substring"function() {

      var a = "foo bar baz";

      expect(a).toContain("bar");

      expect(a).not.toContain("quux");

    });

  });

  it("The 'toBeLessThan' matcher is for mathematical comparisons"function() {

    var pi = 3.1415926,

      e = 2.78;

     

    //小于

    expect(e).toBeLessThan(pi);

    expect(pi).not.toBeLessThan(e);

  });

  it("The 'toBeGreaterThan' matcher is for mathematical comparisons"function() {

    var pi = 3.1415926,

      e = 2.78;

    //大于

    expect(pi).toBeGreaterThan(e);

    expect(e).not.toBeGreaterThan(pi);

  });

  it("The 'toBeCloseTo' matcher is for precision math comparison"function() {

    var pi = 3.1415926,

      e = 2.78;

     

    //临近  是比较两个值是否足够接近(不一定要相等)

    //源码:pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)

    //即  pi - e 的绝对值  是否 小于  10 的 X(2) 次方  / 2

    //以 expect(pi).not.toBeCloseTo(e, 3); 为例,就是 pi 跟 e 的差 绝对值 ,是否小于 1/1000 除以 2 ,即 0.0005 

      

    expect(pi).not.toBeCloseTo(e, 2);

    expect(pi).toBeCloseTo(e, 0);

  });

  it("The 'toThrow' matcher is for testing if a function throws an exception"function() {

    var foo = function() {

      return 1 + 2;

    };

    var bar = function() {

      return a + 1;

    };

    //是否引发异常

    expect(foo).not.toThrow();

    expect(bar).toThrow();

  });

  it("The 'toThrowError' matcher is for testing a specific thrown exception"function() {

    var foo = function() {

      throw new TypeError("foo bar baz");

    };

    //是否抛出指定错误

    expect(foo).toThrowError("foo bar baz");

    expect(foo).toThrowError(/bar/);

    expect(foo).toThrowError(TypeError);

    expect(foo).toThrowError(TypeError, "foo bar baz");

  });

});

//手动制造一个断言失败

//fail函数使specs(测试用例)失败。 它可以将失败消息或Error对象作为参数。

describe("A spec using the fail function"function() {

  var foo = function(x, callBack) {

    if (x) {

      callBack();

    }

  };

  it("should not call the callBack"function() {

    foo(falsefunction() { 

      fail("Callback has been called");

    });

  });

});

//分组相关规则带

//describe 函数用于对相关specs(测试用例)进行分组。 string参数用于命名specs的集合,并且将与specs连接以构成spec的全名。

//这有助于在 测试集 找到规则。 如果你很好地命名他们,你的规则读为传统的BDD风格的完整句子。

describe("A spec"function() {

  it("is just a function, so it can contain any code"function() {

    var foo = 0;

    foo += 1;

    expect(foo).toEqual(1);

  });

  it("can have more than one expectation"function() {

    var foo = 0;

    foo += 1;

    expect(foo).toEqual(1);

    expect(true).toEqual(true);

  });

});

 示例4   beforeEach,afterEach,beforeAll和afterAll函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

//顾名思义,beforeEach函数在调用它的describe中的每个 spec 之前调用一次,afterEach函数在每个spec之后调用一次。

//这里是同一组specs(测试用例)写得有点不同。 被测变量定义在顶层作用域 - 描述块和初始化代码被移入一个beforeEach函数。

//afterEach函数在继续之前重置变量。

describe("A spec using beforeEach and afterEach"function() {

  var foo = 0;

  beforeEach(function() {

    foo += 1;

  });

  afterEach(function() {

    foo = 0;

  });

  it("is just a function, so it can contain any code"function() {

    expect(foo).toEqual(1);

  });

  it("can have more than one expectation"function() {

    expect(foo).toEqual(1);

    expect(true).toEqual(true);

  });

});

//beforeAll函数仅在describe中的所有specs(测试用例)运行之前调用一次,并且afterAll函数在所有specs(测试用例)完成后调用。

//这些功能可用于加快测试集 的昂贵设置和拆卸。

//但是,要小心使用beforeAll和afterAll! 由于它们不在specs(测试用例)之间重置,很容易在specs(测试用例)之间意外泄漏状态,

//使它们错误地通过或失败。  注意跟 beforeEach 的区别,

//如果 在第1个 it 里改变了 foo 的值,第2个 it 的值就不是 初始化时的值了

describe("A spec using beforeAll and afterAll"function() {

  var foo;

  beforeAll(function() {

    foo = 1;

  });

  afterAll(function() {

    foo = 0;

  });

  it("sets the initial value of foo before specs run"function() {

    expect(foo).toEqual(1);

    foo += 1;

  });

  it("does not reset foo between specs"function() {

    expect(foo).toEqual(2);

  });

});

 示例5  this关键字共享变量,嵌套describe

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

//this关键字

//另一种在beforeEach,it和afterEach之间共享变量的方法是通过this关键字。

//每个spec的beforeEach / it / afterEach都将这个作为同一个空对象,对于下一个spec的beforeEach / it / afterEach设置为空。

describe("A spec"function() {

  beforeEach(function() {

    this.foo = 0;

  });

  it("can use the `this` to share state"function() {

    expect(this.foo).toEqual(0);

    this.bar = "test pollution?";

  });

  it("prevents test pollution by having an empty `this` created for the next spec"function() {

    expect(this.foo).toEqual(0);

    //注意这里的区别 undefined

    expect(this.bar).toBe(undefined);

  });

});

//嵌套describe , describe 里嵌套 describe

//调用describe可以嵌套,在任何级别定义specs(测试用例)。 这允许一个单元测试被组成一个函数树。

//在执行specs(测试用例)之前,Jasmine沿着树顺序执行每个beforeEach函数。

//在specs(测试用例)执行后,Jasmine类似地遍历 afterEach 函数。

describe("A spec"function() {

  var foo;

  beforeEach(function() {

    foo = 0;

    foo += 1;

  });

  afterEach(function() {

    foo = 0;

  });

  it("is just a function, so it can contain any code"function() {

    expect(foo).toEqual(1);

  });

  it("can have more than one expectation"function() {

    expect(foo).toEqual(1);

    expect(true).toEqual(true);

  });

  describe("nested inside a second describe"function() {

    var bar;

    beforeEach(function() {

      bar = 1;

    });

    it("can reference both scopes as needed"function() {

      expect(foo).toEqual(bar);

    });

  });

});

 示例6   Pending 待定规则

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//待定规则

//待处理的规则不会运行,但它们的名称将在结果中显示为待处理。

describe("Pending specs"function() {

  //任何用xit声明的spec都被标记为pending。

  xit("can be declared 'xit'"function() {

    expect(true).toBe(false);

  });

 //在没有函数体的情况下声明的任何specs(测试用例)也将在结果中被标记为待处理

  it("can be declared with 'it' but without a function");

//pending() 如果你在specs(测试用例)体中任何地方调用该函数,无论预期如何,specs(测试用例)将被标记为待定。

//pending()函数接受一个字符串参数,该参数会在结果集中显示在 PENDING WITH MESSAGE:之后,作为为何被Pending的原因。

 it("can be declared by calling 'pending' in the spec body"function() {

    expect(true).toBe(false);

    pending('this is why it is pending');

  });

});

 示例7  Spies 对象监控

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

// Spies

//Jasmine有 spies(监控) 双重测试功能。   spy 可以存根任何函数并跟踪对它和所有参数的调用。

//spy 只存在于描述或其定义的块中,并且将在每个specs(测试用例)之后删除。 有特殊的匹配器与 spies 交互。

//Jasmine 2.0的语法已更改。

describe("A spy"function() {

  var foo, bar = null;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      }

    };

    spyOn(foo, 'setBar');

    //spyOn(foo, 'setBar').and.callThrough();

    foo.setBar(123);

    foo.setBar(456, 'another param');

  });

  //如果调用 Spies ,toHaveBeenCalled匹配器将返回true。

  //是否被调用

  it("tracks that the spy was called"function() {

    expect(foo.setBar).toHaveBeenCalled();

  });

  //如果 Spies 被调用了指定的次数,toHaveBeenCalledTimes匹配器将通过。

  it("tracks that the spy was called x times"function() {

    expect(foo.setBar).toHaveBeenCalledTimes(2);

  });

  //如果参数列表匹配任何记录的调用到 Spies ,toHaveBeenCalledWith匹配器将返回true。

  it("tracks all the arguments of its calls"function() {

    expect(foo.setBar).toHaveBeenCalledWith(123);

    expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');

  });

  it("stops all execution on a function"function() {

      

      //有没有感到奇怪,beforeEach 里调用了 foo.setBar(),这里为什么 bar 的值为 null ??

      //原因是 spyOn(foo, 'setBar'); 并不会去调用 真实的 foo.setBar()函数,只是调用了 Jasmine 保存的这个函数的 存根,不会影响到实际的值

      //如果这样写 spyOn(foo, 'setBar').and.callThrough(); 就会调用真实的 foo.setBar()函数了,bar的值也会跟随改变

      expect(bar).toBeNull();

  });

});

// Spies :and.callThrough

//通过使用and.callThrough链接 Spies , Spies 仍然会跟踪对它的所有调用,但此外它将委派给实际的实现。

describe("A spy, when configured to call through"function() {

  var foo, bar, fetchedBar;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      },

      getBar: function() {

        return bar;

      }

    };

    spyOn(foo, 'getBar').and.callThrough();

    foo.setBar(123);

    fetchedBar = foo.getBar();

  });

  it("tracks that the spy was called"function() {

    expect(foo.getBar).toHaveBeenCalled();

  });

  it("should not affect other functions"function() {

    expect(bar).toEqual(123);

  });

  it("when called returns the requested value"function() {

      //这里 fetchedBar 有值

      //这就是 spyOn(foo, 'getBar').and.callThrough() 跟 spyOn(foo, 'getBar') 的区别

      expect(fetchedBar).toEqual(123);

  });

});

// Spies :and.returnValue

//通过使用and.returnValue链接 Spies ,所有对函数的调用都将返回特定的值。

describe("A spy, when configured to fake a return value"function() {

  var foo, bar, fetchedBar;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      },

      getBar: function() {

        return bar;

      }

    };

    spyOn(foo, "getBar").and.returnValue(745);

    foo.setBar(123);

    //所有调用 foo.getBar() 函数都返回 745

    fetchedBar = foo.getBar();

  });

  it("tracks that the spy was called"function() {

    expect(foo.getBar).toHaveBeenCalled();

  });

  it("should not affect other functions"function() {

    expect(bar).toEqual(123);

  });

  it("when called returns the requested value"function() {

    expect(fetchedBar).toEqual(745);

  });

});

// specs :and.returnValues

//通过使用and.returnValues链接 specs ,所有对函数的调用将按顺序返回特定的值,

//直到它到达返回值列表的结尾,此时它将返回未定义的所有后续调用。

describe("A spy, when configured to fake a series of return values"function() {

  var foo, bar;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      },

      getBar: function() {

        return bar;

      }

    };

    spyOn(foo, "getBar").and.returnValues("fetched first""fetched second");

    foo.setBar(123);

  });

  it("tracks that the spy was called"function() {

    //返回调用次数 对应的 参数数组 下标的值

    foo.getBar(123);

    expect(foo.getBar).toHaveBeenCalled();

  });

  it("should not affect other functions"function() {

    //不要迷惑了,赋值是在 beforeEach 里做的,不是 foo.getBar(123);

    expect(bar).toEqual(123);

  });

  it("when called multiple times returns the requested values in order"function() {

    //返回调用次数 对应的 参数数组 下标的值

    expect(foo.getBar()).toEqual("fetched first");

    expect(foo.getBar()).toEqual("fetched second");

    expect(foo.getBar()).toBeUndefined();

  });

});

// specs :and.callFake

//通过使用and.callFake链接 specs ,所有对 specs 的调用都将委派给提供的函数。

describe("A spy, when configured with an alternate implementation"function() {

  var foo, bar, fetchedBar;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      },

      getBar: function() {

        return bar;

      }

    };

    //如果被窥探的函数接收到假的需要的参数,你可以得到那些

    spyOn(foo, "getBar").and.callFake(function(arguments, can, be, received) {

      return 1001;

    });

    foo.setBar(123);

    fetchedBar = foo.getBar();

  });

  it("tracks that the spy was called"function() {

    expect(foo.getBar).toHaveBeenCalled();

  });

  it("should not affect other functions"function() {

    expect(bar).toEqual(123);

  });

  it("when called returns the requested value"function() {

    expect(fetchedBar).toEqual(1001);

  });

});

// specs :and.throwError

//通过使用and.throwError链接 specs ,所有对 specs 的调用都将抛出指定的值作为错误。

describe("A spy, when configured to throw an error"function() {

  var foo, bar;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      }

    };

    spyOn(foo, "setBar").and.throwError("quux");

  });

  it("throws the value"function() {

    expect(function() {

      foo.setBar(123)

    }).toThrowError("quux");

  });

});

// specs :and.stub

//当调用策略用于 specs 时,可以随时使用and.stub返回原始的存根行为。

describe("A spy"function() {

  var foo, bar = null;

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      }

    };

    spyOn(foo, 'setBar').and.callThrough();

  });

  it("can call through and then stub in the same spec"function() {

    foo.setBar(123);

    expect(bar).toEqual(123);

    foo.setBar.and.stub();

    bar = null;

    foo.setBar(123);

    //返回原始的存根

    expect(bar).toBe(null);

  });

});

 在上面这段代码里 ,要注意 Spies :and.callThrough  的用法  注意代码  spyOn(foo, 'getBar').and.callThrough(); 跟 spyOn(foo, 'getBar');  的区别  spyOn(foo, 'getBar').and.callThrough() 会调用实例方法

产生实际的影响,而 spyOn(foo, 'getBar');  只是调用了 Jasmine 保存的这个函数的 存根,不会影响到实际的值 ,如果没看明白请仔细看代码上我添加的注释。

示例8   其他属性

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

describe("A spy"function() {

  var foo, bar = null;

     

  //每个对 specs 的调用都会被跟踪并在calls属性上公开

  beforeEach(function() {

    foo = {

      setBar: function(value) {

        bar = value;

      }

    };

    spyOn(foo, 'setBar');

  });

//.calls.any():如果spy没有被调用,则返回false,如果至少有一个调用发生,则返回true

it("tracks if it was called at all"function() {

    expect(foo.setBar.calls.any()).toEqual(false);

    foo.setBar();

    expect(foo.setBar.calls.any()).toEqual(true);

  });

  //.calls.count():返回调用 specs 的次数

  it("tracks the number of times it was called"function() {

    expect(foo.setBar.calls.count()).toEqual(0);

    foo.setBar();

    foo.setBar();

    expect(foo.setBar.calls.count()).toEqual(2);

  });

//.calls.argsFor(index):返回传递给调用号索引的参数

it("tracks the arguments of each call"function() {

    foo.setBar(123);

    foo.setBar(456, "baz");

    expect(foo.setBar.calls.argsFor(0)).toEqual([123]);

    expect(foo.setBar.calls.argsFor(1)).toEqual([456, "baz"]);

  });

  //.calls.allArgs():返回所有调用的参数

  it("tracks the arguments of all calls"function() {

    foo.setBar(123);

    foo.setBar(456, "baz");

    expect(foo.setBar.calls.allArgs()).toEqual([[123],[456, "baz"]]);

  });

//.calls.all():返回上下文(this)和传递所有调用的参数

it("can provide the context and arguments to all calls"function() {

    foo.setBar(123);

    expect(foo.setBar.calls.all()).toEqual([{object: foo, args: [123], returnValue: undefined}]);

  });

  //.calls.mostRecent():返回上一次调用的上下文(this)和参数

  it("has a shortcut to the most recent call"function() {

    foo.setBar(123);

    foo.setBar(456, "baz");

    expect(foo.setBar.calls.mostRecent()).toEqual({object: foo, args: [456, "baz"], returnValue: undefined});

  });

//.calls.first():返回上下文(this)和第一次调用的参数

 it("has a shortcut to the first call"function() {

    foo.setBar(123);

    foo.setBar(456, "baz");

    expect(foo.setBar.calls.first()).toEqual({object: foo, args: [123], returnValue: undefined});

  });

  //当检查来自all(),mostRecent()和first()的返回时,当调用 specs 时,object属性被设置为this的值。

  it("tracks the context"function() {

    var spy = jasmine.createSpy('spy');

    var baz = {

      fn: spy

    };

    var quux = {

      fn: spy

    };

    baz.fn(123);

    quux.fn(456);

     

    //.object 返回的this ,即调用对象

    expect(spy.calls.first().object).toBe(baz);

    expect(spy.calls.mostRecent().object).toBe(quux);

  });

  //.calls.reset():清除 specs 的所有跟踪

  it("can be reset"function() {

    foo.setBar(123);

    foo.setBar(456, "baz");

    expect(foo.setBar.calls.any()).toBe(true);

    foo.setBar.calls.reset();

    expect(foo.setBar.calls.any()).toBe(false);

  });

});

// specs :createSpy

//当没有一个函数来监视,jasmine.createSpy可以创建一个“裸” specs 。

//这个 specs 作为任何其他 specs  - 跟踪调用,参数等,但其没有实现。  specs 是JavaScript对象,可以这样使用。

describe("A spy, when created manually"function() {

  var whatAmI;

  beforeEach(function() {

    whatAmI = jasmine.createSpy('whatAmI');

    whatAmI("I""am""a""spy");

  });

  it("is named, which helps in error reporting"function() {

    expect(whatAmI.and.identity()).toEqual('whatAmI');

  });

  it("tracks that the spy was called"function() {

    expect(whatAmI).toHaveBeenCalled();

  });

  it("tracks its number of calls"function() {

    expect(whatAmI.calls.count()).toEqual(1);

  });

  it("tracks all the arguments of its calls"function() {

    expect(whatAmI).toHaveBeenCalledWith("I""am""a""spy");

  });

  it("allows access to the most recent call"function() {

    expect(whatAmI.calls.mostRecent().args[0]).toEqual("I");

  });

});

// specs :createSpyObj

//为了创建一个有多个 specs 的模拟,使用jasmine.createSpyObj并传递一个字符串数组。 它返回一个对象,它具有属于 specs 的每个字符串的属性。

describe("Multiple spies, when created manually"function() {

  var tape;

  beforeEach(function() {

    tape = jasmine.createSpyObj('tape', ['play''pause''stop''rewind']);

    tape.play();

    tape.pause();

    tape.rewind(0);

  });

  it("creates spies for each requested function"function() {

    expect(tape.play).toBeDefined();

    expect(tape.pause).toBeDefined();

    expect(tape.stop).toBeDefined();

    expect(tape.rewind).toBeDefined();

  });

  it("tracks that the spies were called"function() {

    expect(tape.play).toHaveBeenCalled();

    expect(tape.pause).toHaveBeenCalled();

    expect(tape.rewind).toHaveBeenCalled();

    expect(tape.stop).not.toHaveBeenCalled();

  });

  it("tracks all the arguments of its calls"function() {

    expect(tape.rewind).toHaveBeenCalledWith(0);

  });

});

//匹配所有与jasmine.any

describe("jasmine.anything"function() {

  //如果实际值不为null或未定义,jasmine.anything返回true。

  it("matches anything"function() {

    expect(1).toEqual(jasmine.anything());

  });

  describe("when used with a spy"function() {

    it("is useful when the argument can be ignored"function() {

      var foo = jasmine.createSpy('foo');

      foo(12, function() {

        return false;

      });

      expect(foo).toHaveBeenCalledWith(12, jasmine.anything());

    });

  });

});

//与jasmine.objectContaining的部分匹配

//jasmine.objectContaining是用于期望在实际中只关心某些键/值对的时候。

describe("jasmine.objectContaining"function() {

  var foo;

  beforeEach(function() {

    foo = {

      a: 1,

      b: 2,

      bar: "baz"

    };

  });

  it("matches objects with the expect key/value pairs"function() {

    //只比对bar

    expect(foo).toEqual(jasmine.objectContaining({

      bar: "baz"

    }));

    expect(foo).not.toEqual(jasmine.objectContaining({

      c: 37

    }));

  });

  describe("when used with a spy"function() {

    it("is useful for comparing arguments"function() {

      var callback = jasmine.createSpy('callback');

      callback({

        bar: "baz"

      });

     

      expect(callback).toHaveBeenCalledWith(jasmine.objectContaining({

        bar: "baz"

      }));

      expect(callback).not.toHaveBeenCalledWith(jasmine.objectContaining({

        c: 37

      }));

    });

  });

});

  

//部分数组与jasmine.arrayContaining相匹配

//jasmine.arrayContaining用于那些期望只关心数组中的某些值的时候。

describe("jasmine.arrayContaining"function() {

  var foo;

  beforeEach(function() {

    foo = [1, 2, 3, 4];

  });

  it("matches arrays with some of the values"function() {

    expect(foo).toEqual(jasmine.arrayContaining([3, 1]));

    expect(foo).not.toEqual(jasmine.arrayContaining([6]));

  });

  describe("when used with a spy"function() {

    it("is useful when comparing arguments"function() {

      var callback = jasmine.createSpy('callback');

      callback([1, 2, 3, 4]);

      expect(callback).toHaveBeenCalledWith(jasmine.arrayContaining([4, 2, 3]));

      expect(callback).not.toHaveBeenCalledWith(jasmine.arrayContaining([5, 2]));

    });

  });

});

//字符串与jasmine.stringMatching匹配

//jasmine.stringMatching用于当你不想完全匹配较大对象中的字符串时,或者匹配 specs 预期中的字符串的一部分。

describe('jasmine.stringMatching'function() {

  it("matches as a regexp"function() {

    expect({foo: 'bar'}).toEqual({foo: jasmine.stringMatching(/^bar$/)});

    expect({foo: 'foobarbaz'}).toEqual({foo: jasmine.stringMatching('bar')});

  });

  describe("when used with a spy"function() {

    it("is useful for comparing arguments"function() {

      var callback = jasmine.createSpy('callback');

      callback('foobarbaz');

      expect(callback).toHaveBeenCalledWith(jasmine.stringMatching('bar'));

      expect(callback).not.toHaveBeenCalledWith(jasmine.stringMatching(/^bar$/));

    });

  });

});

//定制不对称等式测试器

//当您需要检查某个满足特定标准的条件,而不是严格相等时,您还可以通过提供具有asymmetricMatch函数的对象来指定自定义非对称等式测试器。

describe("custom asymmetry"function() {

  var tester = {

    asymmetricMatch: function(actual) {

      var secondValue = actual.split(',')[1];

      return secondValue === 'bar';

    }

  };

  it("dives in deep"function() {

    expect("foo,bar,baz,quux").toEqual(tester);

  });

  describe("when used with a spy"function() {

    it("is useful for comparing arguments"function() {

      var callback = jasmine.createSpy('callback');

      callback('foo,bar,baz');

      expect(callback).toHaveBeenCalledWith(tester);

    });

  });

});

 示例 9  Jasmine 时钟

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

//Jasmine 时钟

//Jasmine 2.0的此语法已更改。 Jasmine时钟可用于测试时间相关代码。

describe("Manually ticking the Jasmine Clock"function() {

  var timerCallback;

 //它安装调用了 jasmine.clock()。安装在需要操纵时间的spec或suite。

  beforeEach(function() {

    timerCallback = jasmine.createSpy("timerCallback");

    jasmine.clock().install();

  });

 //完成恢复原始功能后,请务必卸载时钟。

 afterEach(function() {

    jasmine.clock().uninstall();

  });

   

  //模拟JavaScript超时函数

  //您可以使setTimeout或setInterval同步执行已注册的函数,只有当时钟在时间上向前跳过时。

  //要执行注册的函数,通过jasmine.clock()。tick函数延时时间,该函数 参数为 毫秒。

  it("causes a timeout to be called synchronously"function() {

    setTimeout(function() {

      timerCallback();

    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();

    jasmine.clock().tick(101);

    expect(timerCallback).toHaveBeenCalled();

  });

  it("causes an interval to be called synchronously"function() {

    setInterval(function() {

      timerCallback();

    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();

    jasmine.clock().tick(101);

    expect(timerCallback.calls.count()).toEqual(1);

    jasmine.clock().tick(50);

    expect(timerCallback.calls.count()).toEqual(1);

    jasmine.clock().tick(50);

    expect(timerCallback.calls.count()).toEqual(2);

  });

 //模拟日期

 //Jasmine时钟也可以用来模拟当前日期。

 describe("Mocking the Date object"function(){

    it("mocks the Date object and sets it to a given time"function() {

      var baseTime = new Date(2013, 9, 23);

      //如果你没有为mockDate提供基准时间,它将使用当前日期。

      jasmine.clock().mockDate(baseTime);

      jasmine.clock().tick(50);

      expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);

    });

  });

});

 

示例 10   异步支持

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

//异步支持

//Jasmine 2.0的此语法已更改。 Jasmine还支持运行需要测试异步操作的specs(测试用例)。

describe("Asynchronous specs"function() {

  var value;

 //调用beforeAll,afterAll,beforeEach,afterEach和它可以接受一个可选的单个参数,当异步工作完成时,应该调用。

 beforeEach(function(done) {

    setTimeout(function() {

      value = 0;

      done();

    }, 1);

  });

  //在done函数在调用之前,这个specs(测试用例)不会开始。

  //这个specs(测试用例)将会等待 beforeEach 调用 done() 后执行。

  it("should support async execution of test preparation and expectations"function(done) {

    value++;

    expect(value).toBeGreaterThan(0);

    expect(value).toBe(1);//所以这里value 的值为1

    done();

  });

  //默认情况下,jasmine将等待5秒钟,异步specs(测试用例)在导致超时失败之前完成。

  //如果超时在调用done之前超时,则当前specs(测试用例)将被标记为失败,并且单元测试执行将继续,如同调用完成。

  //如果特定规则应该更快失败或需要更多时间,可以通过向其传递超时值等来调整。

  //如果整个单元测试应该有不同的超时,则可以在任何给定描述之外全局设置jasmine.DEFAULT_TIMEOUT_INTERVAL。

  describe("long asynchronous specs"function() {

    beforeEach(function(done) {

      done();

    }, 1000);

    it("takes a long time"function(done) {

      setTimeout(function() {

        done();

      }, 9000);

    }, 10000);

    afterEach(function(done) {

      done();

    }, 1000);

  });

  //done.fail函数使specs(测试用例)失败,并指示它已完成

  describe("A spec using done.fail"function() {

    var foo = function(x, callBack1, callBack2) {

      if (x) {

        setTimeout(callBack1, 0);

      else {

        setTimeout(callBack2, 0);

      }

    };

    it("should not call the second callBack"function(done) {

      foo(true,

        done,

        function() {

          done.fail("Second callback has been called");

        }

      );

    });

  });

});

 示例11  自定义matcher 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

//通常,项目将要封装用于跨多个规范的自定义匹配代码。 下面是如何创建一个Jasmine兼容的自定义匹配器。

//在其根部的自定义匹配器是比较函数,其获取实际值和期望值。

//这个工厂被传递给Jasmine,理想的情况是调用beforeEach,并且在一个给定的调用中描述的所有规范的范围内。

//定制匹配器在规格之间拆分。 工厂的名称将是在期望的调用的返回值上暴露的匹配器的名称。

var customMatchers = {

    //自定义匹配器工厂传递两个参数:util,它有一组用于匹配器使用的效用函数(见:matchersUtil.js用于当前列表)和customEqualityTesters,

    //如果util.equals被调用,则需要传递。 当调用匹配器时,可以使用这些参数。

    toBeGoofy: function (util, customEqualityTesters) {

        //工厂方法应该返回一个含有比较函数的对象,该函数将被调用以检查期望值。

        return {

            //比较函数第一个参数为实际值 ,第二个参数传递给匹配器本身的值(如果有的话)。

            compare: function (actual, expected) {

                //toBeGoofy接受一个可选的期望参数,所以如果不传递,在这里定义。

                if (expected === undefined) {

                    expected = '';

                }

                var result = {};

                if (result.pass) {

                    //如果未定义,期望将尝试为匹配器创建失败消息。 但是,如果返回值具有message属性,它将用于失败的期望。

                    result.message = "Expected " + actual + " not to be quite so goofy";

                else {

                    //匹配成功,所以自定义失败消息应该出现在负期望的情况下 - 当期望与.not一起使用时。

                    result.message = "Expected " + actual + " to be goofy, but it was not very goofy";

                }

                return result;

            }

        };

    }

};

//调用代码

describe("Custom matcher: 'toBeGoofy'"function() {

    beforeEach(function() {

        jasmine.addMatchers(customMatchers);

    });

    it("is available on an expectation"function () {

        expect({

            hyuk: 'gawrsh'

        }).toBeGoofy();

    });

    it("can take an 'expected' parameter"function () {

        expect({

            hyuk: 'gawrsh is fun'

        }).toBeGoofy('is fun');

    });

    it("can be negated"function () {

        expect({

            hyuk: 'this is fun'

        }).not.toBeGoofy();

    });

});

 看完上面的示例应该在项目中应用没有什么问题了。

相关文章:

前端测试框架 jasmine 的使用

最近的项目在使用AngulaJs,对JS代码的测试问题就摆在了面前。通过对比我们选择了 Karma jasmine ,使用 Jasmine做单元测试 &#xff0c;Karma 自动化完成&#xff0c;当然了如果使用 Karma jasmine 前提是必须安装 Nodejs。 安装好 Nodejs &#xff0c;使用 npm 安装好必要…...

Qwen2-VL视觉大模型微调实战:LaTex公式OCR识别任务(完整代码)

《SwanLab机器学习实战教程》是一个主打「开箱即用」的AI训练系列教程&#xff0c;我们致力于提供完善的数据集、源代码、实验记录以及环境安装方式&#xff0c;手把手帮助你跑起训练&#xff0c;解决问题。 Qwen2-VL是通义千问团队最近开源的大语言模型&#xff0c;由阿里云通…...

「Mac玩转仓颉内测版42」小学奥数篇5 - 圆和矩形的面积计算

本篇将通过 Python 和 Cangjie 双语解决简单的几何问题&#xff1a;计算圆的面积和矩形的面积。通过这道题&#xff0c;学生将掌握如何使用公式解决几何问题&#xff0c;并学会用编程实现数学公式。 关键词 小学奥数Python Cangjie几何计算 一、题目描述 编写一个程序&#…...

Groom Blender to UE5

Groom Blender to UE5 - Character & Animation - Epic Developer Community Forums Hello, 你好&#xff0c; While exporting my “groom” from blender to UE5, I notice that the curves have a minimal resolution in Unreal. However I would like to get the same …...

开发一套ERP 第十弹 图片作为配置文件,本地读取图片,定时更新图片类型

echo Hello World在同一数据库中在建一个图床数据表,产品一,一对应,图片命名 最优的方案&#xff0c;使用 rust 在构建一个 http server 用于管理非数据库资源,也可以将来对接不同的图床&#xff0c;部署方便 考虑到数据库资源和图片资源,都可以被远程访问这种方法最佳...

第七十六条:努力保持故障的原子性

当对象抛出异常之后&#xff0c;通常我们期望这个对象仍然保持在一种定义良好的可用状态之中&#xff0c;即使失败是发生在执行某个操作的过程中间。对于受检的异常而言&#xff0c;这尤为重要&#xff0c;因为调用者期望能从这种异常中进行恢复。一般而言&#xff0c;失败的方…...

Word分栏后出现空白页解决方法

Word分栏后出现空白页解决方法 只需要在后面的空白页设置相同的页面布局(分栏格式)&#xff0c;然后按Ctrl backspace即可删除该空白页。 参考文章&#xff1a;Word分栏出现空白怎么解决。...

基于HTML和CSS的校园网页设计与实现

摘要 随着计算机、互联网与通信技术的进步&#xff0c;Internet在人们的学习、工作和生活中的地位也变得越来越高&#xff0c;校园网站已经成为学校与学生&#xff0c;学生与学生之间交流沟通的重要平台&#xff0c;对同学了解学校内发生的各种事情起到了重要的作用。学校网站…...

【算法day7】字符串:反转与替换

题目引用 反转字符串反转字符串II替换数字 1.反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&am…...

分布式存储厂商

分布式存储 以下是对分布式存储厂商XSKY星辰天合、IOMesh&#xff08;SmartX&#xff09;、SmartX的深度对比&#xff1a; 1. XSKY星辰天合 产品与服务&#xff1a;XSKY星辰天合提供统一存储平台&#xff0c;支持块、文件和对象存储服务。已为近2400家大型政企机构实施部署&…...

合合信息扫描全能王线下体验活动:科技与人文的完美交融

文章目录 前言签到欢迎仪式产品体验智能高清滤镜去除透字效果照片高清修复 破冰行动会议感受 前言 作为合合信息旗下扫描全能王的忠实粉丝&#xff0c;上周&#xff0c;我很荣幸参与了扫描全能王“扫出你的能量buff”快闪活动及技术交流会。这次活动的不仅让我对这款强大的文档…...

单链表在Go语言中的实现与操作

简介 单链表是一种基本的线性数据结构&#xff0c;由节点组成&#xff0c;每个节点存储数据和指向下一个节点的指针。今天&#xff0c;我们将深入探讨如何在Go语言中实现和操作单链表。 单链表的优缺点 优点&#xff1a; 动态内存分配&#xff0c;灵活性高。插入和删除节点操…...

网关整合sentinel无法读取nacos配置问题分析

sentinel无法读取nacos配置问题分析 1.spring-cloud-gateway整合sentinel2.问题现象3.原因猜测4.源码分析4. 结语 最近公司需要上线一个集约项目&#xff0c;虽然为内网项目&#xff0c;但曾经有过内网被攻破&#xff0c;导致内部系统被攻击的案例&#xff0c;且集约系统同时在…...

简化XPath表达式的方法与实践

XPath表达式用于在XML或HTML文档中定位元素。有时候&#xff0c;XPath表达式可能会变得非常冗长和复杂&#xff0c;这不仅难以阅读和维护&#xff0c;而且也可能影响性能。因此&#xff0c;学会如何简化XPath表达式是非常重要的。本文将介绍几种简化XPath表达式的方法&#xff…...

【文件下载】接口传递文件成功和失败时,前端的处理方式

问题 使用bold类型从后端接口获取文件流&#xff0c;获取成功的时候通过a标签下载&#xff1b;失败的时候&#xff0c;后端返回的是json&#xff0c;这个时候就无法向用户展示后端返回的错误提示信息。 思路 根据返回类型是否为 application/json 区分是否返回成功&#xff…...

html+css网页设计马林旅行社移动端4个页面

htmlcss网页设计马林旅行社移动端4个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…...

视频 的 音频通道提取 以及 视频转URL 的在线工具!

视频 的 音频通道提取 以及 视频转URL 的在线工具&#xff01; 工具地址: https://www.lingyuzhao.top/toolsPage/VideoTo.html 它提供了便捷的方法来处理视频文件&#xff0c;具体来说是帮助用户从视频中提取音频轨道&#xff0c;并将视频转换为可以通过网络访问的URL链接。无…...

容易被遗忘的测试用例

网络服务器启动了吗&#xff1f;应用程序服务器启动了吗&#xff1f;数据库上线了吗&#xff1f;测试数据是否预先加载到数据库中&#xff1f;每当我们准备开始测试应用程序时&#xff0c;一切都应该已经准备妥当。 然而&#xff0c;当测试开始后&#xff0c;我们可能会漏掉一些…...

uni-app写的微信小程序如何实现账号密码登录后获取token,并且每天的第一次登录后都会直接获取参数而不是耀重新登录(2)

接uni-app写的微信小程序如何实现账号密码登录后获取token&#xff0c;并且每天的第一次登录后都会直接获取参数而不是耀重新登录&#xff08;1&#xff09;&#xff0c; 在main.js中 import App from ./App// #ifndef VUE3 import Vue from vue import ./uni.promisify.adap…...

统计中间件稳定性指标

目前订单业务域涉及中间件&#xff1a;MySQL、Redis、TiDB、MQ、ES。&#xff08;遗漏项请补充&#xff09; 一、RDS 资源使用率 实例ID实例名称规格maxCPUavgCPUmaxDISKmaxIOPSavgIOPS活跃会话maxTPSavgTPSmaxQPSavgQPS实例风险 慢查询 慢查询会消耗大量的系统资源&#x…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...