diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr
index 15539827385f59ecb5970e20676496bd6cdb7fdf..c21d2f5df7ccf9c566962e5e3340b3d681de1052 100755
--- a/spec/compiler/lexer/lexer_spec.cr
+++ b/spec/compiler/lexer/lexer_spec.cr
@@ -123,18 +123,6 @@ def it_lexes_global_match(globals)
   end
 end
 
-def it_raises_doesnt_fit_in_integer(string, message)
-  it "errors if can't fit #{string} in integer" do
-    lexer = Lexer.new(string)
-    begin
-      lexer.next_token
-      fail "expected to raise"
-    rescue ex : Crystal::SyntaxException
-      ex.message.should eq(message)
-    end
-  end
-end
-
 describe "Lexer" do
   it_lexes "", :EOF
   it_lexes " ", :SPACE
@@ -227,28 +215,28 @@ describe "Lexer" do
   it_lexes_regex "/foo\\sbar/", "foo\\sbar"
   it_lexes_global_match ["$1", "$10"]
 
-  it_raises_doesnt_fit_in_integer "128_i8", "128 doesn't fit in an Int8"
-  it_raises_doesnt_fit_in_integer "-129_i8", "-129 doesn't fit in an Int8"
-  it_raises_doesnt_fit_in_integer "256_u8", "256 doesn't fit in an UInt8"
-  it_raises_doesnt_fit_in_integer "-1_u8", "Invalid negative value -1 for UInt8"
+  assert_syntax_error "128_i8", "128 doesn't fit in an Int8"
+  assert_syntax_error "-129_i8", "-129 doesn't fit in an Int8"
+  assert_syntax_error "256_u8", "256 doesn't fit in an UInt8"
+  assert_syntax_error "-1_u8", "Invalid negative value -1 for UInt8"
 
-  it_raises_doesnt_fit_in_integer "32768_i16", "32768 doesn't fit in an Int16"
-  it_raises_doesnt_fit_in_integer "-32769_i16", "-32769 doesn't fit in an Int16"
-  it_raises_doesnt_fit_in_integer "65536_u16", "65536 doesn't fit in an UInt16"
-  it_raises_doesnt_fit_in_integer "-1_u16", "Invalid negative value -1 for UInt16"
+  assert_syntax_error "32768_i16", "32768 doesn't fit in an Int16"
+  assert_syntax_error "-32769_i16", "-32769 doesn't fit in an Int16"
+  assert_syntax_error "65536_u16", "65536 doesn't fit in an UInt16"
+  assert_syntax_error "-1_u16", "Invalid negative value -1 for UInt16"
 
-  it_raises_doesnt_fit_in_integer "2147483648_i32", "2147483648 doesn't fit in an Int32"
-  it_raises_doesnt_fit_in_integer "-2147483649_i32", "-2147483649 doesn't fit in an Int32"
-  it_raises_doesnt_fit_in_integer "4294967296_u32", "4294967296 doesn't fit in an UInt32"
-  it_raises_doesnt_fit_in_integer "-1_u32", "Invalid negative value -1 for UInt32"
+  assert_syntax_error "2147483648_i32", "2147483648 doesn't fit in an Int32"
+  assert_syntax_error "-2147483649_i32", "-2147483649 doesn't fit in an Int32"
+  assert_syntax_error "4294967296_u32", "4294967296 doesn't fit in an UInt32"
+  assert_syntax_error "-1_u32", "Invalid negative value -1 for UInt32"
 
-  it_raises_doesnt_fit_in_integer "9223372036854775808_i64", "9223372036854775808 doesn't fit in an Int64"
-  it_raises_doesnt_fit_in_integer "-9223372036854775809_i64", "-9223372036854775809 doesn't fit in an Int64"
-  it_raises_doesnt_fit_in_integer "118446744073709551616_u64", "118446744073709551616 doesn't fit in an UInt64"
-  it_raises_doesnt_fit_in_integer "18446744073709551616_u64", "18446744073709551616 doesn't fit in an UInt64"
-  it_raises_doesnt_fit_in_integer "-1_u64", "Invalid negative value -1 for UInt64"
+  assert_syntax_error "9223372036854775808_i64", "9223372036854775808 doesn't fit in an Int64"
+  assert_syntax_error "-9223372036854775809_i64", "-9223372036854775809 doesn't fit in an Int64"
+  assert_syntax_error "118446744073709551616_u64", "118446744073709551616 doesn't fit in an UInt64"
+  assert_syntax_error "18446744073709551616_u64", "18446744073709551616 doesn't fit in an UInt64"
+  assert_syntax_error "-1_u64", "Invalid negative value -1 for UInt64"
 
-  it_raises_doesnt_fit_in_integer "18446744073709551616", "18446744073709551616 doesn't fit in an UInt64"
+  assert_syntax_error "18446744073709551616", "18446744073709551616 doesn't fit in an UInt64"
 
   it "lexes not instance var" do
     lexer = Lexer.new "!@foo"
@@ -325,25 +313,8 @@ describe "Lexer" do
     token.type.should eq(:EOF)
   end
 
-  it "raises unterminated regular expression" do
-    lexer = Lexer.new("/foo")
-    begin
-      lexer.next_token
-      fail "expected to raise"
-    rescue ex : Crystal::SyntaxException
-      ex.message.should eq("unterminated regular expression")
-    end
-  end
-
-  it "raises unterminated quoted symbol" do
-    lexer = Lexer.new(":\"foo")
-    begin
-      lexer.next_token
-      fail "expected to raise"
-    rescue ex : Crystal::SyntaxException
-      ex.message.should eq("unterminated quoted symbol")
-    end
-  end
+  assert_syntax_error "/foo", "unterminated regular expression"
+  assert_syntax_error ":\"foo", "unterminated quoted symbol"
 
   it "lexes utf-8 char" do
     lexer = Lexer.new "'á'"
@@ -375,13 +346,5 @@ describe "Lexer" do
     token.type.should eq(:NUMBER)
   end
 
-  it "raises if slash r without slash n" do
-    lexer = Lexer.new("\r1")
-    begin
-      lexer.next_token
-      fail "expected to raise"
-    rescue ex : Crystal::SyntaxException
-      ex.message.should eq("expected '\\n' after '\\r'")
-    end
-  end
+  assert_syntax_error "\r1", "expected '\\n' after '\\r'"
 end
diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 709c62a08c5696d6e2691c0ca4012404afe0cc4a..1c2e0284015543d9b750737990a01fb8a98f1162 100755
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -81,7 +81,7 @@ class String
   end
 
   def symbol
-    Crystal::SymbolLiteral.new self
+    SymbolLiteral.new self
   end
 
   def static_array_of(size)
@@ -106,8 +106,6 @@ def it_parses(string, expected_node)
   end
 end
 
-include Crystal
-
 describe "Parser" do
   it_parses "nil", NilLiteral.new
 
@@ -555,24 +553,24 @@ describe "Parser" do
 
   it_parses "$foo", Global.new("$foo")
 
-  it_parses "macro foo;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([] of ASTNode))
-  it_parses %(macro foo; 1 + 2; end), Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
-  it_parses %(macro foo x; 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
-  it_parses %(macro foo x\n 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
-  it_parses %(macro foo(x); 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
-  it_parses %(macro foo(x)\n 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
-  it_parses "macro foo; 1 + 2 {{foo}} 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode))
-  it_parses "macro foo; 1 + 2 {{ foo }} 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% for x in y %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% for x, y in z %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var, "y".var], "z".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% if x %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% if x %}body{% else %}body2{%end%}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, "body2".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% if x %}body{% elsif y %}body2{%end%}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, MacroIf.new("y".var, "body2".macro_literal)), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% unless x %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, Nop.new, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-
-  it_parses "macro foo;bar{% for x in y %}\\  \n   body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo;bar{% for x in y %}\\  \n   body{% end %}\\   baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
-  it_parses "macro foo; 1 + 2 {{foo}}\\ 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), "3 + 4; ".macro_literal] of ASTNode))
+  it_parses "macro foo;end", Macro.new("foo", [] of Arg, Expressions.from([] of ASTNode))
+  it_parses %(macro foo; 1 + 2; end), Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
+  it_parses %(macro foo x; 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
+  it_parses %(macro foo x\n 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
+  it_parses %(macro foo(x); 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
+  it_parses %(macro foo(x)\n 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode))
+  it_parses "macro foo; 1 + 2 {{foo}} 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode))
+  it_parses "macro foo; 1 + 2 {{ foo }} 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% for x in y %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% for x, y in z %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var, "y".var], "z".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% if x %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% if x %}body{% else %}body2{%end%}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, "body2".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% if x %}body{% elsif y %}body2{%end%}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, MacroIf.new("y".var, "body2".macro_literal)), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% unless x %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, Nop.new, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+
+  it_parses "macro foo;bar{% for x in y %}\\  \n   body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo;bar{% for x in y %}\\  \n   body{% end %}\\   baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode))
+  it_parses "macro foo; 1 + 2 {{foo}}\\ 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), "3 + 4; ".macro_literal] of ASTNode))
 
   it_parses "def foo : String; 1; end", Def.new("foo", [] of Arg, [MacroLiteral.new(" 1; ")] of ASTNode, nil, nil, "String".path)
   it_parses "def foo(x) : String; 1; end", Def.new("foo", ["x".arg], [MacroLiteral.new(" 1; ")] of ASTNode, nil, nil, "String".path)
@@ -821,110 +819,30 @@ describe "Parser" do
     node.instance_vars.should eq(Set.new(["@x"]))
   end
 
-  it "errors if arg doesn't have a default value after a previous one has one" do
-    assert_syntax_error "def foo(x = 1, y); end",
-      "argument must have a default value"
-  end
-
-  it "says unterminated array literal" do
-    begin
-      Parser.parse(" [1, 2, 3 end")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated array literal").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(2)
-    end
-  end
-
-  it "says unterminated hash literal" do
-    begin
-      Parser.parse(" {1 => end")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated hash literal").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(2)
-    end
-  end
-
-  it "says unterminated tuple literal" do
-    begin
-      Parser.parse(" {1, 2, 3 end")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated tuple literal").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(2)
-    end
-  end
-
-  it "says unterminated parenthesized expression" do
-    begin
-      Parser.parse(" (1, 2, 3 end")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated parenthesized expression").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(2)
-    end
-  end
-
-  it "says unterminated call" do
-    begin
-      Parser.parse("foo(1, 2, 3 end")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated call").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(4)
-    end
-  end
-
-  it "says unterminated call with block arg" do
-    begin
-      Parser.parse("foo(foo(&.block)")
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unterminated call").should be_true
-      ex.line_number.should eq(1)
-      ex.column_number.should eq(4)
-    end
-  end
-
-  it "can't parse implicit call in value-less case" do
-    begin
-      Parser.parse("case when .foo? then 1; end")
-      fail "syntax exception should have been raised"
-    rescue ex : Crystal::SyntaxException
-    end
-  end
-
-  it "says unexpected end in macro" do
-    begin
-      Parser.parse "macro foo;{%end};end"
-      fail "syntax exception should have been raised"
-    rescue ex : Crystal::SyntaxException
-    end
-  end
-
-  it "says unexpected token on comma in curly block" do
-    begin
-      Parser.parse "foo {1, 2}"
-      fail "syntax exception should have been raised"
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("unexpected token: }").should be_true
-    end
-  end
-
-  it "says error on pointerof(self)" do
-    begin
-      Parser.parse "pointerof(self)"
-      fail "syntax exception should have been raised"
-    rescue ex : Crystal::SyntaxException
-      ex.message.not_nil!.includes?("can't take pointerof(self)").should be_true
-    end
-  end
-
-  it "says error on def foo 1" do
-    begin
-      Parser.parse "def foo 1; end"
-      fail "syntax exception should have been raised"
-    rescue ex : Crystal::SyntaxException
-    end
-  end
+  assert_syntax_error "def foo(x = 1, y); end",
+                      "argument must have a default value"
+
+  assert_syntax_error " [1, 2, 3 end",
+                      "unterminated array literal", 1, 2
+
+  assert_syntax_error " {1 => end",
+                      "unterminated hash literal", 1, 2
+
+  assert_syntax_error " {1, 2, 3 end",
+                      "unterminated tuple literal", 1, 2
+
+  assert_syntax_error " (1, 2, 3 end",
+                      "unterminated parenthesized expression", 1, 2
+
+  assert_syntax_error "foo(1, 2, 3 end",
+                      "unterminated call", 1, 4
+
+  assert_syntax_error "foo(foo(&.block)",
+                      "unterminated call", 1, 4
+
+  assert_syntax_error "case when .foo? then 1; end"
+  assert_syntax_error "macro foo;{%end};end"
+  assert_syntax_error "foo {1, 2}", "unexpected token: }"
+  assert_syntax_error "pointerof(self)", "can't take pointerof(self)"
+  assert_syntax_error "def foo 1; end"
 end
diff --git a/spec/compiler/type_inference/block_spec.cr b/spec/compiler/type_inference/block_spec.cr
index 19cabc3807f6a56be06c9f4274dce7543bd97caa..24bca74569ca36e8a8c60518bfc78b0b09013bd6 100755
--- a/spec/compiler/type_inference/block_spec.cr
+++ b/spec/compiler/type_inference/block_spec.cr
@@ -285,10 +285,8 @@ describe "Block inference" do
       "expected block to return Foo, not Int32"
   end
 
-  it "errors when block varaible shadows local variable" do
-    assert_syntax_error "a = 1; foo { |a| }",
-      "block argument 'a' shadows local variable 'a'"
-  end
+  assert_syntax_error "a = 1; foo { |a| }",
+                      "block argument 'a' shadows local variable 'a'"
 
   it "errors when using local varaible with block argument name" do
     assert_error "def foo; yield; end; foo { |a| }; a",
diff --git a/spec/compiler/type_inference/exception_spec.cr b/spec/compiler/type_inference/exception_spec.cr
index 8923fd2396927a2820051cc6846d27f9a495959d..10a4af87d405f1d03cf87795a84bef7930fa6745 100644
--- a/spec/compiler/type_inference/exception_spec.cr
+++ b/spec/compiler/type_inference/exception_spec.cr
@@ -137,9 +137,8 @@ describe "Type inference: exception" do
       ") { |mod| union_of(mod.int32, mod.nil) }
   end
 
-  it "errors if exception var shadows local var" do
-    assert_syntax_error "ex = 1; begin; rescue ex; end", "exception variable 'ex' shadows local variable 'ex'"
-  end
+  assert_syntax_error "ex = 1; begin; rescue ex; end",
+                      "exception variable 'ex' shadows local variable 'ex'"
 
   it "errors if catched exception is not a subclass of Exception" do
     assert_error "begin; rescue ex : Int32; end", "Int32 is not a subclass of Exception"
@@ -153,17 +152,14 @@ describe "Type inference: exception" do
     assert_error "begin; rescue ex; end; ex", "undefined local variable or method 'ex'"
   end
 
-  it "errors if catch-all rescue before specific rescue" do
-    assert_syntax_error "begin; rescue ex; rescue ex : Foo; end; ex", "specific rescue must come before catch-all rescue"
-  end
+  assert_syntax_error "begin; rescue ex; rescue ex : Foo; end; ex",
+                      "specific rescue must come before catch-all rescue"
 
-  it "errors if catch-all rescue specified twice" do
-    assert_syntax_error "begin; rescue ex; rescue; end; ex", "catch-all rescue can only be specified once"
-  end
+  assert_syntax_error "begin; rescue ex; rescue; end; ex",
+                      "catch-all rescue can only be specified once"
 
-  it "errors if else without rescue" do
-    assert_syntax_error "begin; else; 1; end", "'else' is useless without 'rescue'"
-  end
+  assert_syntax_error "begin; else; 1; end",
+                      "'else' is useless without 'rescue'"
 
   it "types code with abstract exception that delegates method" do
     assert_type(%(
diff --git a/spec/compiler/type_inference/fun_spec.cr b/spec/compiler/type_inference/fun_spec.cr
index 8745370e15852a6f1dab0127fbbea2fe1e7dea09..f7272fa0609b3ced5e768f3a61c013c924c27331 100644
--- a/spec/compiler/type_inference/fun_spec.cr
+++ b/spec/compiler/type_inference/fun_spec.cr
@@ -67,10 +67,8 @@ describe "Type inference: fun" do
       ") { float64 }
   end
 
-  it "errors when fun varaible shadows local variable" do
-    assert_syntax_error "a = 1; ->(a : Foo) { }",
-      "function argument 'a' shadows local variable 'a'"
-  end
+  assert_syntax_error "a = 1; ->(a : Foo) { }",
+                      "function argument 'a' shadows local variable 'a'"
 
   it "errors when using local varaible with fun argument name" do
     assert_error "->(a : Int32) { }; a",
diff --git a/spec/compiler/type_inference/var_spec.cr b/spec/compiler/type_inference/var_spec.cr
index c8f8c44b795262a52ba3a2014fcfe5b63aba5e5c..a5ee9c3e2a50fb5b0383f6fa97c785bc651196da 100755
--- a/spec/compiler/type_inference/var_spec.cr
+++ b/spec/compiler/type_inference/var_spec.cr
@@ -37,10 +37,8 @@ describe "Type inference: var" do
     ", "undefined local variable or method 'something'"
   end
 
-  it "reports read before assignment" do
-    assert_syntax_error "a += 1",
-      "'+=' before definition of 'a'"
-  end
+  assert_syntax_error "a += 1",
+                      "'+=' before definition of 'a'"
 
   it "reports read before assignment" do
     assert_error "a = a + 1",
@@ -51,9 +49,8 @@ describe "Type inference: var" do
     assert_error "self", "there's no self in this scope"
   end
 
-  it "reports can't change the value of self" do
-    assert_syntax_error "self = 1", "can't change the value of self"
-  end
+  assert_syntax_error "self = 1",
+                      "can't change the value of self"
 
   it "reports variable always nil" do
     assert_error "1 == 2 ? (a = 1) : a",
diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr
index 41ceeabf000c555835ddd5f4966bbed85e26b5d5..15873697d15a321e3c76ccb068a1b435d3bfe7b1 100644
--- a/spec/spec_helper.cr
+++ b/spec/spec_helper.cr
@@ -72,22 +72,41 @@ def assert_after_type_inference(before, after)
   result.node.to_s.strip.should eq(after.strip)
 end
 
+def assert_syntax_error(str)
+  it "says syntax error on #{str.inspect}" do
+    expect_raises Crystal::SyntaxException do
+      parse str
+    end
+  end
+end
+
 def assert_syntax_error(str, message)
-  begin
-    parse str
-    fail "SyntaxException wasn't raised"
-  rescue ex : Crystal::SyntaxException
-    fail "Expected '#{ex}' to contain '#{message}'" unless ex.to_s.includes? message
+  it "says syntax error on #{str.inspect}" do
+    expect_raises Crystal::SyntaxException, message do
+      parse str
+    end
+  end
+end
+
+def assert_syntax_error(str, message, line, column)
+  it "says syntax error on #{str.inspect}" do
+    begin
+      Parser.parse(str)
+      fail "expected SyntaxException to be raised"
+    rescue ex : SyntaxException
+      ex.message.not_nil!.includes?(message).should be_true
+      ex.line_number.should eq(line)
+      ex.column_number.should eq(column)
+    end
   end
 end
 
 def assert_error(str, message)
-  nodes = parse str
-  begin
-    infer_type nodes
-    fail "TypeException wasn't raised"
-  rescue ex : Crystal::TypeException
-    fail "Expected '#{ex}' to contain '#{message}'" unless ex.to_s.includes? message
+  it "says type error on #{str.inspect}" do
+    nodes = parse str
+    expect_raises TypeException, message do
+      infer_type nodes
+    end
   end
 end
 
diff --git a/spec/std/array_spec.cr b/spec/std/array_spec.cr
index 48ae29838fa9de45c34c9a904fdeb0432c88a19e..79d615eccd47c91c2a0e3df3191167ab1e4062fe 100755
--- a/spec/std/array_spec.cr
+++ b/spec/std/array_spec.cr
@@ -144,11 +144,9 @@ describe "Array" do
     end
 
     it "deletes out of bounds" do
-      begin
-        a = [1, 2, 3, 4]
+      a = [1, 2, 3, 4]
+      expect_raises IndexOutOfBounds do
         a.delete_at(4)
-        fail "Expected to raise IndexOutOfBounds"
-      rescue IndexOutOfBounds
       end
     end
   end
@@ -303,10 +301,8 @@ describe "Array" do
   end
 
   it "raises if out of bounds" do
-    begin
+    expect_raises IndexOutOfBounds do
       [1, 2, 3][4]
-      fail "Expected [] to raise"
-    rescue IndexOutOfBounds
     end
   end
 
@@ -324,10 +320,8 @@ describe "Array" do
     end
 
     it "raises when empty" do
-      begin
+      expect_raises IndexOutOfBounds do
         ([] of Int32).pop
-        fail "expected to raise IndexOutOfBounds"
-      rescue IndexOutOfBounds
       end
     end
 
@@ -346,11 +340,9 @@ describe "Array" do
     end
 
     it "pops negative count raises" do
-      begin
-        a = [1, 2]
+      a = [1, 2]
+      expect_raises ArgumentError do
         a.pop(-1)
-        fail "exepcted to raise ArgumentError"
-      rescue ArgumentError
       end
     end
   end
@@ -363,10 +355,8 @@ describe "Array" do
     end
 
     it "raises when empty" do
-      begin
+      expect_raises IndexOutOfBounds do
         ([] of Int32).shift
-        fail "expected to raise IndexOutOfBounds"
-      rescue IndexOutOfBounds
       end
     end
 
@@ -385,11 +375,9 @@ describe "Array" do
     end
 
     it "shifts negative count raises" do
-      begin
-        a = [1, 2]
+      a = [1, 2]
+      expect_raises ArgumentError do
         a.shift(-1)
-        fail "exepcted to raise ArgumentError"
-      rescue ArgumentError
       end
     end
   end
@@ -401,10 +389,8 @@ describe "Array" do
     end
 
     it "raises when empty" do
-      begin
+      expect_raises IndexOutOfBounds do
         ([] of Int32).first
-        fail "expected to raise IndexOutOfBounds"
-      rescue IndexOutOfBounds
       end
     end
   end
@@ -427,10 +413,8 @@ describe "Array" do
     end
 
     it "raises when empty" do
-      begin
+      expect_raises IndexOutOfBounds do
         ([] of Int32).last
-        fail "expected to raise IndexOutOfBounds"
-      rescue IndexOutOfBounds
       end
     end
   end
@@ -513,10 +497,8 @@ describe "Array" do
     end
 
     it "gets sample of negative count elements raises" do
-      begin
+      expect_raises ArgumentError do
         [1].sample(-1)
-        fail "expected to raise ArgumentError"
-      rescue ArgumentError
       end
     end
 
@@ -590,19 +572,15 @@ describe "Array" do
 
     it "swaps but raises out of bounds on left" do
       a = [1, 2, 3]
-      begin
+      expect_raises IndexOutOfBounds do
         a.swap(3, 0)
-        fail "expected swap to fail"
-      rescue IndexOutOfBounds
       end
     end
 
     it "swaps but raises out of bounds on right" do
       a = [1, 2, 3]
-      begin
+      expect_raises IndexOutOfBounds do
         a.swap(0, 3)
-        fail "expected swap to fail"
-      rescue IndexOutOfBounds
       end
     end
   end
diff --git a/spec/std/bit_array_spec.cr b/spec/std/bit_array_spec.cr
index aadfafdef37966cccb273628616a2cb33989515d..01674c9f671b0871b36095704843f9fe5c30d5f4 100644
--- a/spec/std/bit_array_spec.cr
+++ b/spec/std/bit_array_spec.cr
@@ -50,10 +50,8 @@ describe "BitArray" do
 
   it "is raises when out of bounds" do
     ary = BitArray.new(10)
-    begin
+    expect_raises IndexOutOfBounds do
       ary[10] = true
-      fail "expected IndexOutOfBounds to be raised"
-    rescue IndexOutOfBounds
     end
   end
 
diff --git a/spec/std/cast_spec.cr b/spec/std/cast_spec.cr
index d3131cfb6941683c5df52d5dd1d966b9daa9353f..0baaa73cec5e11809419a2dead778fe1ea369f0c 100644
--- a/spec/std/cast_spec.cr
+++ b/spec/std/cast_spec.cr
@@ -40,11 +40,8 @@ describe "Cast" do
 
   it "casts from union to single type raises" do
     a = 1 || 'a'
-    begin
+    expect_raises Exception, "type cast exception" do
       a as Char
-      fail "expected cast to raise"
-    rescue ex
-      ex.message.should eq("type cast exception")
     end
   end
 
@@ -56,11 +53,8 @@ describe "Cast" do
 
   pending "casts from union to another union raises" do
     a = 1 || 1.5 || 'a'
-    begin
+    expect_raises Exception, "type cast exception" do
       a as Float64 | Char
-      fail "expected cast to raise"
-    rescue ex
-      ex.message.should eq("type cast exception")
     end
   end
 
@@ -72,11 +66,8 @@ describe "Cast" do
 
   it "casts from hierarchy to single type raises" do
     a = CastSpecBar.new || CastSpecFoo.new || CastSpecBaz.new
-    begin
+    expect_raises Exception, "type cast exception" do
       a as CastSpecBaz
-      fail "expected cast to raise"
-    rescue ex
-      ex.message.should eq("type cast exception")
     end
   end
 
diff --git a/spec/std/char_reader_spec.cr b/spec/std/char_reader_spec.cr
index c4cabf64641d0083dfb31a70ab99f38fbf173bf0..ac955a10912743eee18d0fdfe613c6d2ad54ff86 100644
--- a/spec/std/char_reader_spec.cr
+++ b/spec/std/char_reader_spec.cr
@@ -9,7 +9,7 @@ describe "CharReader" do
     reader.current_char.ord.should eq(0)
     reader.has_next?.should be_false
 
-    expect_raise IndexOutOfBounds do
+    expect_raises IndexOutOfBounds do
       reader.next_char
     end
   end
@@ -22,7 +22,7 @@ describe "CharReader" do
     reader.next_char.ord.should eq(0)
     reader.has_next?.should be_false
 
-    expect_raise IndexOutOfBounds do
+    expect_raises IndexOutOfBounds do
       reader.next_char
     end
   end
@@ -46,7 +46,7 @@ describe "CharReader" do
     reader.next_char.ord.should eq(0)
     reader.has_next?.should be_false
 
-    expect_raise IndexOutOfBounds do
+    expect_raises IndexOutOfBounds do
       reader.next_char
     end
   end
diff --git a/spec/std/dir_spec.cr b/spec/std/dir_spec.cr
index f3ba9d6b0c73a4498610016ceafe1f0589ebe406..5cb6d672bbd50488a95260d40cea729cc80554a6 100755
--- a/spec/std/dir_spec.cr
+++ b/spec/std/dir_spec.cr
@@ -23,10 +23,8 @@ describe "Dir" do
   end
 
   it "tests mkdir with an existing path" do
-    begin
+    expect_raises Errno do
       Dir.mkdir(__DIR__, 0700)
-      fail "Expected Errno to be raised"
-    rescue Errno
     end
   end
 
@@ -34,33 +32,27 @@ describe "Dir" do
     path = "/tmp/crystal_mkdir_ptest_#{Process.pid}/"
     Dir.mkdir_p(path).should eq(0)
     Dir.exists?(path).should be_true
-    path = File.join({path, "a", "b", "c"})    
+    path = File.join({path, "a", "b", "c"})
     Dir.mkdir_p(path).should eq(0)
     Dir.exists?(path).should be_true
   end
 
   it "tests mkdir_p with an existing path" do
     Dir.mkdir_p(__DIR__).should eq(0)
-    begin
+    expect_raises Errno do
       Dir.mkdir_p(__FILE__)
-      fail "Expected Errno to be raised"
-    rescue Errno
     end
   end
 
   it "tests rmdir with an nonexistent path" do
-    begin
+    expect_raises Errno do
       Dir.rmdir("/tmp/crystal_mkdir_test_#{Process.pid}/")
-      fail "Expected Errno to be raised"
-    rescue Errno
     end
   end
 
   it "tests rmdir with a path that cannot be removed" do
-    begin
+    expect_raises Errno do
       Dir.rmdir(__DIR__)
-      fail "Expected Errno to be raised"
-    rescue Errno
     end
   end
 end
diff --git a/spec/std/enumerable_spec.cr b/spec/std/enumerable_spec.cr
index 8ed37eab2613b2f63872a6c53b145697c02a91d0..c532091a2d17cd280972226c938c7fb8f65f5df8 100755
--- a/spec/std/enumerable_spec.cr
+++ b/spec/std/enumerable_spec.cr
@@ -21,10 +21,8 @@ describe "Enumerable" do
     assert { [1, 2, 3].inject(10) { |memo, i| memo + i }.should eq(16) }
 
     it "raises if empty" do
-      begin
+      expect_raises EmptyEnumerable do
         ([] of Int32).inject { |memo, i| memo + i }
-        fail "expected inject to raise"
-      rescue EmptyEnumerable
       end
     end
   end
@@ -33,10 +31,8 @@ describe "Enumerable" do
     assert { [1, 2, 3].min.should eq(1) }
 
     it "raises if empty" do
-      begin
+      expect_raises EmptyEnumerable do
         ([] of Int32).min
-        fail "expected inject to raise"
-      rescue EmptyEnumerable
       end
     end
   end
@@ -45,10 +41,8 @@ describe "Enumerable" do
     assert { [1, 2, 3].max.should eq(3) }
 
     it "raises if empty" do
-      begin
+      expect_raises EmptyEnumerable do
         ([] of Int32).max
-        fail "expected inject to raise"
-      rescue EmptyEnumerable
       end
     end
   end
@@ -57,10 +51,8 @@ describe "Enumerable" do
     assert { [1, 2, 3].minmax.should eq({1, 3}) }
 
     it "raises if empty" do
-      begin
+      expect_raises EmptyEnumerable do
         ([] of Int32).minmax
-        fail "expected inject to raise"
-      rescue EmptyEnumerable
       end
     end
   end
diff --git a/spec/std/file_spec.cr b/spec/std/file_spec.cr
index 83ceea3e5ffbf2116ca92bd0e412393d58a20b0c..72f2854d34148cc6759dab1c8d4220f4f3e234ec 100755
--- a/spec/std/file_spec.cr
+++ b/spec/std/file_spec.cr
@@ -101,10 +101,8 @@ describe "File" do
   end
 
   it "gets stat for non-existent file and raises" do
-    begin
+    expect_raises Errno do
       File.stat("non-existent")
-      fail "expected Errno to be raised"
-    rescue Errno
     end
   end
 
@@ -128,10 +126,8 @@ describe "File" do
 
     it "raises errno when file doesn't exist" do
       filename = "#{__DIR__}/data/temp1.txt"
-      begin
+      expect_raises Errno do
         File.delete(filename)
-        fail "expected Errno to be raised"
-      rescue Errno
       end
     end
   end
@@ -150,10 +146,8 @@ describe "File" do
 
     it "raises if old file doesn't exist" do
       filename = "#{__DIR__}/data/temp1.txt"
-      begin
+      expect_raises Errno do
         File.rename(filename, "#{filename}.new")
-        fail "expected Errno to be raised"
-      rescue Errno
       end
     end
   end
diff --git a/spec/std/hash_spec.cr b/spec/std/hash_spec.cr
index 2dea546750364910a35da76be5b1ce9aff6b6e04..6ea2403f9b84619310bd289a1fc608a4b44b065f 100755
--- a/spec/std/hash_spec.cr
+++ b/spec/std/hash_spec.cr
@@ -109,10 +109,8 @@ describe "Hash" do
 
     it "fetches and raises" do
       a = {1 => 2}
-      begin
+      expect_raises Exception, "Missing hash value: 2" do
         a.fetch(2)
-        fail "expected fetch to raise"
-      rescue
       end
     end
   end
diff --git a/spec/std/json/parser_spec.cr b/spec/std/json/parser_spec.cr
index 62c46b2a8b957e5fb70f7fac4cb106fa9643a5d9..c342998920c64b14e58e24bfa33c9e2a6d0aca33 100644
--- a/spec/std/json/parser_spec.cr
+++ b/spec/std/json/parser_spec.cr
@@ -9,10 +9,8 @@ end
 
 def it_raises_on_parse_json(string)
   it "raises on parse #{string}" do
-    begin
+    expect_raises Json::ParseException do
       Json.parse(string)
-      fail "expected Json.parse to raise"
-    rescue Json::ParseException
     end
   end
 end
diff --git a/spec/std/json/pull_parser_spec.cr b/spec/std/json/pull_parser_spec.cr
index 0ec6c9774f77597bd1f8ad1162f0a745c203a540..9f1df382d6829593d05a276a9904f96edb90aedd 100644
--- a/spec/std/json/pull_parser_spec.cr
+++ b/spec/std/json/pull_parser_spec.cr
@@ -86,9 +86,9 @@ class Json::PullParser
   end
 
   def assert_error
-    read_next
-    fail "expected to raise"
-  rescue Json::ParseException
+    expect_raises Json::ParseException do
+      read_next
+    end
   end
 end
 
@@ -102,13 +102,11 @@ end
 
 def assert_pull_parse_error(string)
   it "errors on #{string}" do
-    begin
+    expect_raises Json::ParseException do
       parser = Json::PullParser.new string
       while parser.kind != :EOF
         parser.read_next
       end
-      fail "expected to raise"
-    rescue Json::ParseException
     end
   end
 end
diff --git a/spec/std/option_parser_spec.cr b/spec/std/option_parser_spec.cr
index f19293d443fe771c96343dadff15231c39079964..97c646cbdc3036f5647805cb05ed9ac51308aa3e 100755
--- a/spec/std/option_parser_spec.cr
+++ b/spec/std/option_parser_spec.cr
@@ -25,22 +25,21 @@ describe "OptionParser" do
   end
 
   def expect_missing_option(option)
-    OptionParser.parse([] of String) do |opts|
-      opts.on(option, "some flag") do |flag_value|
+    expect_raises OptionParser::MissingOption do
+      OptionParser.parse([] of String) do |opts|
+        opts.on(option, "some flag") do |flag_value|
+        end
       end
     end
-    fail "expected OptionParser::MissingOption to be raised"
-  rescue ex : OptionParser::MissingOption
   end
 
   def expect_missing_option(args, option, flag)
-    OptionParser.parse(args) do |opts|
-      opts.on(option, "some flag") do |flag_value|
+    expect_raises OptionParser::MissingOption, "Missing option: #{flag}" do
+      OptionParser.parse(args) do |opts|
+        opts.on(option, "some flag") do |flag_value|
+        end
       end
     end
-    fail "expected OptionParser::MissingOption to be raised"
-  rescue ex : OptionParser::MissingOption
-    ex.message.should eq("Missing option: #{flag}")
   end
 
   it "has flag" do
@@ -155,13 +154,10 @@ describe "OptionParser" do
   end
 
   it "raises on invalid option" do
-    begin
+    expect_raises OptionParser::InvalidOption, "Invalid option: -j" do
       OptionParser.parse(["-f", "-j"]) do |opts|
         opts.on("-f", "some flag") { }
       end
-      fail "Expected to raise OptionParser::InvalidOption"
-    rescue ex : OptionParser::InvalidOption
-      ex.message.should eq("Invalid option: -j")
     end
   end
 
diff --git a/spec/std/random_spec.cr b/spec/std/random_spec.cr
index 59a41c2f7a8a8f2685dc6d1840a2506a65bcd15b..88a1cc766e03fcecd7af04622fe5f118beecc3bd 100755
--- a/spec/std/random_spec.cr
+++ b/spec/std/random_spec.cr
@@ -17,11 +17,8 @@ describe "Random" do
   end
 
   it "raises on invalid number" do
-    begin
+    expect_raises ArgumentError, "incorrect rand value: 0" do
       rand(0)
-      fail "expect rand(0) to raise"
-    rescue ex
-      ex.message.should eq("incorrect rand value: 0")
     end
   end
 
@@ -40,11 +37,8 @@ describe "Random" do
   end
 
   it "raises on invalid range" do
-    begin
+    expect_raises ArgumentError, "incorrect rand value: 1...1" do
       rand(1...1)
-      fail "expect rand(1...1) to raise"
-    rescue ex
-      ex.message.should eq("incorrect rand value: 1...1")
     end
   end
 end
diff --git a/spec/std/regexp_spec.cr b/spec/std/regexp_spec.cr
index fb85c246c3ffa467bec40505385f4afaebcf9b8a..97e76ee7d7c4b57bffeb360b13892ccaad309727 100755
--- a/spec/std/regexp_spec.cr
+++ b/spec/std/regexp_spec.cr
@@ -19,19 +19,15 @@ describe "Regex" do
 
   it "raises if outside match range with []" do
     "foo" =~ /foo/
-    begin
+    expect_raises IndexOutOfBounds do
       $1
-      fail "Expected $1 to raise"
-    rescue ex : IndexOutOfBounds
     end
   end
 
   it "raises if outside match range with begin" do
     "foo" =~ /foo/
-    begin
+    expect_raises IndexOutOfBounds do
       $1
-      fail "Expected $1 to raise"
-    rescue ex : IndexOutOfBounds
     end
   end
 
diff --git a/src/random.cr b/src/random.cr
index 83a528c7f40b4f803818a8612ac03b046dcb99f2..3297377a4522a0ba0523af588f4fa4e0b0feaf42 100644
--- a/src/random.cr
+++ b/src/random.cr
@@ -21,7 +21,7 @@ def rand(x : Int)
   if x > 0
     C.rand % x
   else
-    raise "incorrect rand value: #{x}"
+    raise ArgumentError.new "incorrect rand value: #{x}"
   end
 end
 
@@ -31,6 +31,6 @@ def rand(x : Range(Int32, Int32))
   if span > 0
     x.begin + rand(span)
   else
-    raise "incorrect rand value: #{x}"
+    raise ArgumentError.new "incorrect rand value: #{x}"
   end
 end
diff --git a/src/spec.cr b/src/spec.cr
index f3f81cd1397fb815552c745a32180552e62bb4f5..c9885c7911c9ed7c64aac9893b4a35e1f520ad27 100644
--- a/src/spec.cr
+++ b/src/spec.cr
@@ -226,7 +226,15 @@ def fail(msg)
   raise Spec::AssertionFailed.new(msg)
 end
 
-macro expect_raise(klass)
+macro expect_raises
+  begin
+    {{yield}}
+    fail "expected to raise"
+  rescue
+  end
+end
+
+macro expect_raises(klass)
   begin
     {{yield}}
     fail "expected to raise {{klass.id}}"
@@ -234,6 +242,26 @@ macro expect_raise(klass)
   end
 end
 
+macro expect_raises(klass, message)
+  begin
+    {{yield}}
+    fail "expected to raise {{klass.id}}"
+  rescue _ex_ : {{klass.id}}
+    _msg_ = {{message}}
+    _ex_to_s_ = _ex_.to_s
+    case _msg_
+    when Regex
+      unless (_ex_to_s_ =~ _msg_)
+        fail "expected {{klass.id}}'s message to match #{_msg_}, but was #{_ex_to_s_.inspect}"
+      end
+    when String
+      unless _ex_to_s_.includes?(_msg_)
+        fail "expected {{klass.id}}'s message to include #{_msg_.inspect}, but was #{_ex_to_s_.inspect}"
+      end
+    end
+  end
+end
+
 class Object
   def should(expectation)
     unless expectation.match self