2

我想定义匹配器来检查解析器是否可以接受字符串。我做到了,但感觉不好。

Dart 单元测试代码:

library test_parser;

import 'package:unittest/unittest.dart';
import '../lib/shark_parser.dart';

main() {
  SharkParser parser;
  setUp(() {
    parser = new SharkParser();
  });
  tearDown(() {
    parser = null;
  });

  group("paramType parser", () {
    test("should accept valid types", () {
      expect(parser.paramType(), accept("String"));
      expect(parser.paramType(), accept("int"));
      expect(parser.paramType(), accept("List"));
      expect(parser.paramType(), accept("List<User>"));
    });
    test("should not accept invalid types", () {
      expect(parser.paramType(), notAccept("#"));
      expect(parser.paramType(), notAccept("0"));
      expect(parser.paramType(), notAccept("String()"));
      expect(parser.paramType(), notAccept("List< User >"));
    });
  });
}

自定义匹配器:

Matcher accept(String matchingString) => new AcceptMatcher(matchingString);

Matcher notAccept(String matchingString) => new NotAcceptMatcher(matchingString);

class NotAcceptMatcher extends Matcher {
  String matchingString;

  NotAcceptMatcher(this.matchingString);

  bool matches(item, Map matchState) {
    return !item.end().accept(matchingString);
  }

  Description describe(Description description) {
    return description.add("parser not accept string: $matchingString");
  }

  Description describeMismatch(item, Description mismatchDescription,
                               Map matchState, bool verbose) {
    mismatchDescription.add("accepts it");
    return mismatchDescription;
  }
}

class AcceptMatcher extends Matcher {

  String matchingString;

  AcceptMatcher(this.matchingString);

  bool matches(item, Map matchState) {
    return item.end().accept(matchingString);
  }

  Description describe(Description description) {
    return description.add("parser accept string: $matchingString");
  }

  Description describeMismatch(item, Description mismatchDescription,
                               Map matchState, bool verbose) {
    mismatchDescription.add("doesn't accept");
    return mismatchDescription;
  }

}

你可以看到我必须定义两个匹配器NotAcceptMatcherAcceptMatcher. 逻辑非常相似,但我不知道如何使其简单。

还有其他更简单的解决方案吗?

4

1 回答 1

2

You can use the isNot matcher to invert your accept matcher:

expect(parser.paramType(), isNot(accept("#")));

It reads a little funny, so you can create a function to do it:

Matcher notAccept(String s) => isNot(accept(s));

expect(parser.paramType(), notAccept("#"));

The description might not read perfectly, but it saves you some work.

Matchers might seem verbose, but if you want you can make your matcher definition a little more concise by shedding some type annotations and using short variable names. I find this an ok tradeoff when I'm writing a class or function to be called by a framework, because I'm not worried about documenting it for other users.

class AcceptMatcher extends Matcher {
  final acceptString;

  AcceptMatcher(this.acceptString);

  matches(item, _) => item.end().accept(acceptString);

  describe(d) => d.add("parser accept string: $acceptString");

  describeMismatch(item, d, _, __) => d..add("doesn't accept");
}

Another option is to just use the predicate matcher:

Matcher accept(String s) => 
    predicate((i) => i.end().accept(s), "parser accepts $s");
于 2014-02-17T00:06:27.647 回答