dart_test:如果根据`setUp`中分配的数据使用了`test`之前的循环,如何执行`setUp`?

xkrw2x1b  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(93)

问题就出在这段代码中:

void main() {
  late List<int> data;

  setUp(() async {
    data = [11, 22, 33];
  });
  
  int counter = 0;
  for (final d in data) { // error
    test('data', () {
      expect(d, data[counter++]);
    });
  }
}

字符串

错误

Local 'data' has not been initialized.

  • 如何指定setUp函数应该在数据被使用之前被调用?*

我尝试在group中 Package test-同样的错误。

x6yk4ghg

x6yk4ghg1#

setUptest接受 callbacks 作为参数,这些参数将在以后某个未指定的时间执行,但具有一定的相对顺序。具体来说,setUp注册了一个回调,该回调将在每个test回调执行之前执行。
以下是事件的顺序:

  1. setUp注册其回调。
    1.执行for-循环。
  2. test在循环的每次迭代中被调用,注册一个回调。
  3. for-循环退出。
    1.执行测试,每个测试包括:
    1.执行步骤1中的setUp回调。
    1.执行步骤3中的test回调。
    for-loop不存在于test回调函数中;它在setUp注册其回调函数后立即执行。没有办法在for-loop之前自动执行setUp回调函数。如果你真的想这样做,你可以显式地将回调函数设置为一个显式调用的命名函数:
void main() {
  late List<int> data;

  void setUpAction() {
    data = [11, 22, 33];
  }

  setUp(setUpAction);
  setUpAction();
  
  int counter = 0;
  for (final d in data) {
    test('data', () {
      expect(d, data[counter++]);
    });
  }
}

字符串
然而,setUp应该在执行每个测试之前用于重置共享状态,但是您的测试不会改变任何共享状态。因此,在您的情况下,您甚至不需要setUp

void main() {
  const data = [11, 22, 33];

  int counter = 0;
  for (final d in data) {
    test('data', () {
      expect(d, data[counter++]);
    });
  }
}

bsxbgnwa

bsxbgnwa2#

@jamesdlin的回答帮了大忙,这要感谢他。下面的代码演示了这种行为:

void main() {
  late List<int> data;

  void setUpCustom([int? numb]) {
    print('with $numb: setUp called');
    data = [11, 22, if (numb != null) numb];
  }

  setUp(setUpCustom);
  tearDown(() {
    print('tearDown called');
    data = [];
  });

  setUpCustom(33);
  int counter = 0;
  for (final d in data) {
    test('data', () {
      print('in test: $d, $counter $data');
      expect(d, data[counter++]);
    });
  }

  setUpCustom(44);
  //...
}

字符串
将打印:

with 33: setUp called
with 44: setUp called
with null: setUp called
in test: 11, 0 [11, 22]
tearDown called
with null: setUp called
in test: 22, 1 [11, 22]
tearDown called
with null: setUp called
in test: 33, 2 [11, 22]
dart:core             List.[]
test\test.dart 97:21  main.<fn>
tearDown called

RangeError (index): Invalid value: Not in inclusive range 0..1: 2


如果您不打算使用setUpCustom中的参数,这可能是完全可行的。

n9vozmp4

n9vozmp43#

经过两天的努力,我找到了一个最佳解决方案,它允许您使用收集集并在测试时准确地调用setUptearDown
看,这里有一个简单的 Package :

@isTest
Future<void> testWith(
  Object description,
  dynamic Function() body, {
  dynamic Function()? setUp,
  dynamic Function()? tearDown,
}) async {
  test(description, () async {
    await setUp?.call();
    await body.call();
    await tearDown?.call();
  });
}

字符串
根据需要添加所需的参数。也可以是异步的,工作正常。
现在我们可以执行以下代码(稍微扩展以展示功能):

Future<void> main() async {
  late List<int> data;
  Future<void> setUpAction() async {
    print('setUpAction');
    data = [11, 22, 33];
  }

  Future<void> tearDownAction() async {
    print('tearDownAction');
    data = [];
  }

  await testWith(
    'Test_1 data',
    setUp: setUpAction,
    tearDown: tearDownAction,
    () {
      int counter = 0;
      for (final d in data) {
        print('test_1: $d');
        expect(d, data[counter++]);
      }
    },
  );

  await testWith(
    'Test_2 data',
    setUp: setUpAction,
    tearDown: tearDownAction,
    () {
      int counter = 0;
      for (final d in data.take(2)) {
        print('test_1: $d');
        expect(d, data[counter++]);
      }
    },
  );
}


控制台的输出如下:

setUpAction
test_1: 11
test_1: 22
test_1: 33
tearDownAction
setUpAction
test_1: 11
test_1: 22
tearDownAction


如果我们使用这个answer中的setUpAction,我们会遇到两个问题:

  • 调用setUpAction将发生两次,我们将测试不完全是什么意图
  • 没有可能使用多个测试,因为所有的测试都被收集到一个列表中,然后才开始执行。2这一点已经被证明了here

添加isTest注解,这样idea就可以看到来自meta包的测试(如果需要,还有一个isTestGroup注解):
用于注解运行单个测试的测试框架函数。工具(如IDE)可以在文件结构视图中显示此类函数的调用,以帮助用户在大型测试文件中导航。函数的第一个参数必须是测试的描述。

相关问题