我今天遇到了Dart的奇怪行为.我对局部变量和词法范围的理解肯定有问题.让我们进入一些代码.上下文是测试分数从数字到字母的转换,但这并不是理解的关键.

首先,考虑这段代码,它的工作方式与预期一致:

void main() {
  final pairs = <List>[
    [95, 'A'],
    [85, 'B'],
  ];

  for (final pair in pairs) {
    int number = pair[0];
    String letter = pair[1];
    test('$number converts to $letter', () {
      final actual = convert(number);
      expect(actual, letter);
    });
  }
}

String convert(int value) => value >= 90 ? 'A' : 'B';

运行测试,它通过了.将第二行测试数据从85更改为95,则第二次测试失败.我明白这一点.

现在考虑这个替代实现.注意,唯一的区别是现在在for循环之外声明了numberletter变量.

void main() {
  final pairs = <List>[
    [95, 'A'],
    [85, 'B'],
  ];

  int number;
  String letter;

  for (final pair in pairs) {
    number = pair[0];
    letter = pair[1];
    test('$number converts to $letter', () {
      final actual = convert(number);
      expect(actual, letter);
    });
  }
}

String convert(int value) => value >= 90 ? 'A' : 'B';

按原样运行这段代码会产生预期的结果:两个测试成功,它们的名称分别是"95个转换为A"和"85个转换为B".但是,现在将测试数据中的85更改为95.现在,有both次测试失败.测试的名字正如人们所预料的:"95个转换为A"和"95个转换为B".

我已经try 在测试方法中设置断点来解决这个问题.当测试运行时,第一个测试的名称是"95转换为A",但在该测试体中,值letter是"B".

我已经和编程语言打交道很长时间了,但我还是目瞪口呆.有人能给我解释一下这里发生了什么事吗?我不明白为什么这两个程序会有不同的表现.

推荐答案

测试框架的工作方式是,它运行一次来查找所有测试,但还不实际执行测试体.

然后,测试运行者运行它在第一遍中收集的测试.

您的代码创建一组变量,并在第一次传递中为它们赋值两次,并注册两个测试. 然后运行测试,两个测试都会看到变量的最新赋值.

这就是为什么您需要通过在循环中创建变量来确保变量对于对test的调用是唯一的,或者确保由setUp调用来初始化变量,因为每次测试都会调用这些变量.

Dart相关问答推荐

如何在将构造函数参数赋给最终变量和传递给超级构造函数之前操作它?

数字到字符串的转换在 Dart 中总是不变的(即没有文化)?

自定义主题无法正常工作

ListView 不会刷新,而附加列表会刷新 (Flutter)

使用 2 个类型参数声明类型StateNotifierProvider,但给出了 1 个类型参数

flutter: 使用提供程序时,状态在热重载时丢失

Flutter/Dart 为 Google Maps Marker 添加自定义点击事件

如何实现 Iterable

自定义声音推送通知不起作用

Flutter更新导航栏

不要将 PageView 居中 - Flutter

Flutter中图像纵横比的变化

从Dart中的另一个文件导入扩展名方法

使用 dart 下载文件

如何在 Dart 中获取字符串的字节数?

Dart 中 await for 和 listen 的区别

如何在 Dart 中从外部查询 shadow DOM 中的元素?

如何在 Dart 中获取文件名?

Dart 中的 Math.round() 在哪里?

dart中是否可以有一个私有构造函数?