厌倦了非语义测试以弥补动态类型 – 建议?

在我开始学习计算机工程之前,我曾经在Rails(之前的PHP)中做过很多Web编程。

从那时起,我在C中完成了大量的学习工作,并在Objective-C(Mac的东西)中完成了一些个人工作。 我学会了喜欢静态打字。

但现在我不得不做一些专业的网页开发(自由职业),并再次获得了Rails。 我发现编写非语义类型检查测试真的很烦人。 我从C和Objective-C编译器中免费获得这些。 我喜欢点击Build并让系统检查我的所有代码,看A可以调用B,B可以调用一些模糊的库C等等。我所要做的只是测试语义。 但是对于Rails,我是编译器。 🙁

有人走过同样的道路吗? 我是使用C#和Java + x框架进行Web MVC的唯一选择吗? 寻找一些建议,甚至是一些同情……:P

顺便说一句,我特别提到了Rails而不是Ruby,因为我不介意Ruby的动态特性,比如脚本或其他简单的东西。 但由于Rails依赖于如此多的gem,并且由于通常会添加许多其他gem,因此动态类型成为一个问题。

谢谢!

编辑:

我跟进了pst的建议并调查了Scala。 在阅读由Scala创作者Martin Odersky撰写的“Scala编程”一书时,我发现了这一段文本,它在很多方面表达了我的关注和更多。 非常有趣的阅读。

摘自Martin Odersky的Scala编程第52页:

Scala是静态类型的

静态类型系统根据它们保存和计算的值的类型对变量和表达式进行分类。 Scala是一种具有非常先进的静态类型系统的语言。 从类似Java的嵌套类类型系统开始,它允许您使用generics参数化类型,使用交叉组合类型,以及使用抽象类型隐藏类型的详细信息。 这些为构建和组合您自己的类型奠定了坚实的基础,因此您可以设计同时安全且灵活使用的界面。

如果您喜欢Perl,Python,Ruby或Groovy等动态语言,您可能会发现Scala的静态类型系统被列为其优势之一有点奇怪。 毕竟,有些人认为缺少静态类型系统是动态语言的主要优势。 反对静态类型的最常见的论点是它们使程序过于冗长,阻止程序员按照自己的意愿表达自己,并且使得软件系统的某些动态修改模式变得不可能。

但是,这些参数通常不会违反静态类型的概念,而是针对特定类型系统,这些系统被认为过于冗长或过于僵化。 例如,Smalltalk语言的发明者Alan Kay曾经说过:“我不反对类型,但我不知道任何类型的系统并不是一个完全痛苦,所以我仍然喜欢动态打字。”

我们希望在本书中说服Scala的类型系统远非“完全痛苦”。事实上,它很好地解决了静态类型的两个常见问题:通过类型推断避免了冗长,通过模式匹配获得了灵活性以及编写和撰写类型的几种新方法。 有了这些障碍,可以更好地理解静态类型系统的经典优势。 其中最重要的好处是程序抽象,安全重构和更好的文档的可validation属性。

可validation的属性

静态类型系统可以certificate没有某些运行时错误。 例如,他们可以certificate以下属性:布尔值永远不会被添加到整数; 私有变量不能从他们的课外访问; 函数应用于正确数量的参数; 只有字符串被添加到一组字符串中。

今天的静态类型系统没有检测到其他类型的错误。 例如,它们通常不会检测非终止函数,数组边界违规或除零。 他们也不会检测到你的程序不符合其规范(假设有一个规范,那就是!)。 因此,一些人认为静态类型系统不是很有用。 该论点认为,由于此类型系统只能检测简单错误,而unit testing提供更广泛的覆盖范围,为什么还要使用静态类型呢?

我们认为这些论点忽视了这一点。 虽然静态类型系统当然不能取代unit testing,但它可以通过处理一些本来需要测试的属性来减少所需的unit testing数量。 同样,unit testing不能取代静态类型。 毕竟,正如Edsger Dijkstra所说,测试只能certificate存在错误,而不是缺席。 因此,静态类型提供的保证可能很简单,但它们是forms的真正保证,没有多少测试可以提供。

安全的重构

静态类型系统提供了一个安全网,使您可以高度自信地更改代码库。 例如,考虑一个为方法添加附加参数的重构。 在静态类型语言中,您可以进行更改,重新编译系统并简单地修复导致类型错误的所有行。 完成此操作后,您确定已找到所有需要更改的位置。 对于许多其他简单的重构也是如此,例如更改方法名称或将方法从一个类移动到另一个类。 在所有情况下,静态类型检查将提供足够的保证,使新系统像旧系统一样工作。

文档

静态类型是程序文档,编译器会检查它是否正确。 与普通注释不同,类型注释永远不会过时(至少在包含它的源文件最近通过编译器时不会)。 此外,编译器和集成开发环境可以使用类型注释来提供更好的上下文帮助。 例如,集成开发环境可以通过确定进行选择的表达式的静态类型并查找该类型的所有成员来显示可供选择的所有成员。

这是我对动态语言的“抱怨”之一。 我想测试语义,而不是类型错误;-)话虽如此,一个好的测试框架/设置在所有非平凡的情况下都是必须的,良好的代码覆盖和经过测试的要求非常重要。

如果你想沿着JVM上的静态类型路径(我有),我强烈建议你看一下Scala 。 来自Ruby,与Java相比,它的痛苦(实际上以不同的方式实现很多乐趣)要少得多。 你可以“保留”你认为理所当然的东西 – 基于表达式的语法,闭包,在许多地方省略类型的能力(不像Ruby那样开放,但是你确实得到了编译时类型检查;-),一切(*) – 是一个对象OO,统一的访问器方法,轻松构建DSL的能力,以及糖 – 并通过本地类型推断,模式匹配,相对丰富的集合框架获得静态类型语言的好处,以及与Java的良好集成(包括众多的Web框架,还有一些Scala特定的框架,它们利用了Scala语言)。

C#3.0 / 4.0(和.NET3.5 +)也不是太破旧 (但是避免使用C#2.0,现在希望它是遗物),引入了LINQ /闭包,基本类型推断和其他优秀的语言function我发现大多数任务都“可以接受”(猜猜我如何评价Java作为一种语言;-)。 但是,C#是一种CLR目标语言(有一个.NET Scala端口,但我不确定状态 – 它不是主要的目标平台)。

既然我已经提到了Scala,我还应该提到F#(现在是一种“官方”的.NET语言),它将“与OO一起使用”的方法与OCaml类似 – Scala更像是反向,我将它描述为“OO”function“。 我听说过/反对F#与C#wrt类型系统相比,但没有F#的实际经验。 你可能喜欢也可能不喜欢这种范式转变。

快乐的编码。

当你提到Rails,并且鉴于你对Scala感兴趣,你一定要检查一下。 这是2008年对其创作者的采访 ,以及2009年的一次演讲 (video),我将其链接起来,因为虽然陈旧,但他们将Lift与其他语言的替代品进行比较。

但是,如果Lift不是您的事,请放心,还有其他Scala Web框架 。

这种类型的测试通常不在Rails中完成。 不要因为必须这样做而烦恼,不要担心它。 或者也许可以更好地解释为什么你认为这是一个问题,因为大多数Rails程序员都没有。

更新

编写test_include_with_order_works的人确保Rails在这种特殊情况下将符号解释为字符串。 这似乎不是你必须测试的东西,因为Rails已经为你提供并测试了这个function。 坦率地说,我有点惊讶,任何人都会担心符号是否会像字符串一样运作。 我们都知道它可以并且经常这样做。

一般来说,我认为Rails框架必须确保您不需要的东西,以使其实现符合其设计。 我相信动态类型语言的工作原理是客户端代码不会传递会破坏他们调用的方法的参数。 如果他们这样做,他们就无法调用这些方法。 您不必浪费时间确保您的方法在提供太多参数时会抛出exception,而您的方法可以轻松(并且应该)忽略额外的参数。

所以,我不确定你提供的例子是否真的certificate了在Rails中进行非语义测试的必要性。