test_xml 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +31 -0
  4. data/README.rdoc +56 -73
  5. data/Rakefile +12 -12
  6. data/lib/test_xml.rb +0 -2
  7. data/lib/test_xml/matcher_methods.rb +29 -0
  8. data/lib/test_xml/mini_test.rb +6 -0
  9. data/lib/test_xml/nokogiri/node.rb +13 -8
  10. data/lib/test_xml/spec.rb +1 -4
  11. data/lib/test_xml/spec/matchers.rb +5 -4
  12. data/lib/test_xml/spec/matchers/{match_xml.rb → contain_xml.rb} +2 -7
  13. data/lib/test_xml/spec/matchers/{match_xml_structure.rb → contain_xml_structure.rb} +2 -5
  14. data/lib/test_xml/spec/matchers/{exactly_match_xml.rb → equal_xml.rb} +2 -7
  15. data/lib/test_xml/spec/matchers/{exactly_match_xml_structure.rb → equal_xml_structure.rb} +2 -4
  16. data/lib/test_xml/test_unit.rb +2 -0
  17. data/lib/test_xml/test_unit/assertions.rb +29 -32
  18. data/lib/test_xml/version.rb +1 -1
  19. data/spec/{lib/test_xml/spec/matchers/match_xml_spec.rb → matchers/contain_xml_spec.rb} +5 -5
  20. data/spec/{lib/test_xml/spec/matchers/match_xml_structure_spec.rb → matchers/contain_xml_structure_spec.rb} +4 -4
  21. data/spec/{lib/test_xml/spec/matchers/exactly_match_xml_spec.rb → matchers/equal_xml_spec.rb} +6 -4
  22. data/spec/{lib/test_xml/spec/matchers/exactly_match_xml_structure_spec.rb → matchers/equal_xml_structure_spec.rb} +4 -4
  23. data/spec/spec.opts +2 -0
  24. data/spec/spec_helper.rb +1 -4
  25. data/test/{test_xml/nokogiri → nokogiri}/test_node.rb +14 -7
  26. data/test/test_helper.rb +1 -4
  27. data/test/test_unit/test_assertions.rb +227 -0
  28. data/test_xml.gemspec +28 -0
  29. metadata +77 -42
  30. data/test/test_xml/test_unit/test_assertions.rb +0 -159
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rspec', ">= 2.2"
7
+ gem 'rdoc'
8
+ end
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ test_xml (0.0.4)
5
+ nokogiri (>= 1.3.2)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ nokogiri (1.4.4)
12
+ rake (0.8.7)
13
+ rdoc (3.5.3)
14
+ rspec (2.5.0)
15
+ rspec-core (~> 2.5.0)
16
+ rspec-expectations (~> 2.5.0)
17
+ rspec-mocks (~> 2.5.0)
18
+ rspec-core (2.5.1)
19
+ rspec-expectations (2.5.0)
20
+ diff-lcs (~> 1.1.2)
21
+ rspec-mocks (2.5.0)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ rake
28
+ rdoc
29
+ rspec (>= 2.2)
30
+ rspec-core (~> 2.2)
31
+ test_xml!
@@ -1,24 +1,46 @@
1
1
  = TestXml
2
2
 
3
+
3
4
  == DESCRIPTION:
4
5
 
5
- TestXml is a small extension for RSpec and TestUnit for XML/HTML testing. I have found it very useful for API testing with our Cucumber tests.
6
+ TestXml is a small extension for testing XML/HTML. Extending RSpec and TestUnit it makes asserting and comparing XML snippets easy, and is especially helpful for testing RESTful web services and their XML representations.
7
+
6
8
 
7
9
  == FEATURES:
8
10
 
9
- * test XML with: RSpec, Test::Unit, Cucumber
10
- * test XML structure (partially or fully matched)
11
- * test the element values within XML structure
11
+ * runs with RSpec2, Test::Unit, MiniTest and Cucumber
12
+ * Ruby 1.8 and 1.9
13
+ * test XML structure and content
14
+
15
+
16
+ == INSTALL
17
+
18
+ gem install test_xml
19
+
12
20
 
13
21
  == EXAMPLES:
14
22
 
15
- === Cucumber feature
23
+ === Test::Unit and MiniTest
24
+
25
+ def test_item_representation
26
+ assert_xml_equal "<item><id>1</id></item>", @item.to_xml
27
+ end
28
+
29
+ === RSpec
30
+
31
+ it "should contain the id" do
32
+ @item.to_xml.should equal_xml(<<-XML)
33
+ <item>
34
+ <id>1</id>
35
+ </item>
36
+ XML
37
+ end
38
+
39
+ === Cucumber
16
40
 
17
41
  Scenario:
18
- Given data
19
- When I post the data
20
- The I receive successful response
21
- And response matches the following xml
42
+ When I post some data
43
+ Then the response should match the following xml
22
44
  """
23
45
  <transaction>
24
46
  <status>success</status>
@@ -27,97 +49,58 @@ TestXml is a small extension for RSpec and TestUnit for XML/HTML testing. I have
27
49
  </transaction>
28
50
  """
29
51
 
30
- The scenario will check:
31
-
32
- * 'status' element and its value.
33
- * 'id' and 'order_id' elements are present in XML
34
-
35
52
  == USAGE:
36
53
 
37
54
  === RSpec
38
55
 
39
- in spec_helper.rb
56
+ In your spec_helper.rb
40
57
 
41
- require 'test_xml'
42
58
  require 'test_xml/spec'
43
59
 
44
- in spec file:
45
-
46
- it "should match_xml" do
47
- xml = <<-XML
48
- <root>
49
- <one>1</one>
50
- <two>2</two>
51
- </root>
52
- XML
53
-
54
- xml.should match_xml(<<-XML)
55
- <root>
56
- <one>1</one>
57
- <two>2</two>
58
- </root>
59
- XML
60
- end
61
-
62
- === Implemented matchers
60
+ And in the actual spec, use these matchers:
63
61
 
64
- * match_xml
65
- * exactly_match_xml
66
- * match_xml_structure
67
- * exactly_match_xml_structure
62
+ * equal_xml
63
+ * contain_xml
64
+ * equal_xml_structure
65
+ * contain_xml_structure
68
66
 
69
- === With Test::Unit
67
+ === Test::Unit
70
68
 
71
- in test_helper.rb
69
+ In the test_helper.rb
72
70
 
73
- require 'test_xml'
74
71
  require 'test_xml/test_unit'
75
72
 
76
- in test file:
73
+ In your test file, use these matchers:
77
74
 
78
- def test_that_xml_matches
79
- xml = <<-XML
80
- <root>
81
- <one>1</one>
82
- </root>
83
- XML
75
+ * assert_xml_equal
76
+ * assert_xml_contain
77
+ * assert_xml_structure_equal
78
+ * assert_xml_structure_contain
84
79
 
85
- assert_match_xml(xml) do
86
- <<-XML
87
- <root>
88
- <one>1</one>
89
- </root>
90
- XML
91
- end
92
- end
80
+ Negative assertions are available as <tt>assert_not_*</tt>.
81
+
82
+ === MiniTest
93
83
 
94
- === Implemented assertions
84
+ In the test_helper.rb
95
85
 
96
- * assert_match_xml
97
- * assert_exactly_match_xml
98
- * assert_match_xml_structure
99
- * assert_exactly_match_xml_structure
86
+ require 'test_xml/mini_test'
100
87
 
101
- with assert_not_*
88
+ Check the Test::Unit section for available assertions.
102
89
 
103
- === With Cucumber
90
+ === Cucumber
104
91
 
105
- Add to features/env.rb
92
+ In the features/env.rb
106
93
 
107
94
  require 'test_xml'
108
95
  require 'test_xml/spec'
109
96
  World(TestXml::Spec)
110
97
 
111
- And you can add the following step:
112
-
113
- Then /^response matches the following xml$/ do |string|
98
+ In your steps file e.g. features/step_definitions/xml_steps.rb add this step:
99
+
100
+ Then /^the response should match the following xml$/ do |string|
114
101
  response.body.should match_xml(string)
115
102
  end
116
103
 
117
104
  == REQUIREMENTS
118
105
 
119
- test_xml depends on Nokogiri
120
-
121
- == INSTALL
122
-
123
- [sudo] gem install test_xml
106
+ * nokogiri
data/Rakefile CHANGED
@@ -1,22 +1,22 @@
1
- require 'rubygems'
2
- require 'rake'
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ Bundler.setup
4
+
3
5
  require 'rake/testtask'
4
- require 'spec/rake/spectask'
6
+ require 'rspec/core/rake_task'
5
7
  require 'rdoc/task'
6
8
 
7
- task :default => ['test:units', :spec]
9
+ task :default => ['test', :spec]
8
10
 
9
- namespace :test do
10
- Rake::TestTask.new(:units) do |t|
11
- t.test_files = FileList['test/**/test_*.rb']
12
- t.libs << "test"
13
- t.verbose = true
14
- end
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.test_files = FileList['test/**/test_*.rb']
13
+ t.libs << "test"
14
+ t.verbose = true
15
15
  end
16
16
 
17
17
 
18
- Spec::Rake::SpecTask.new do |t|
19
- t.libs << "spec"
18
+ RSpec::Core::RakeTask.new do |t|
19
+ #t.libs << "spec"
20
20
  t.verbose = true
21
21
  end
22
22
 
@@ -1,5 +1,3 @@
1
- require 'rubygems'
2
1
  require 'nokogiri'
3
-
4
2
  require 'test_xml/nokogiri/node'
5
3
  require 'test_xml/nokogiri'
@@ -0,0 +1,29 @@
1
+ module TestXml
2
+ # This module implements the actual matchers with their conditions.
3
+ module MatcherMethods
4
+ def self.xml_contain(subject, pattern)
5
+ actual, expected = parse_xml(subject, pattern)
6
+ actual.match?(expected, true)
7
+ end
8
+
9
+ def self.xml_equal(subject, pattern)
10
+ actual, expected = parse_xml(subject, pattern)
11
+ actual.match?(expected, true) && expected.match?(actual, true)
12
+ end
13
+
14
+ def self.xml_structure_contain(subject, pattern)
15
+ actual, expected = parse_xml(subject, pattern)
16
+ actual.match?(expected)
17
+ end
18
+
19
+ def self.xml_structure_equal(subject, pattern)
20
+ actual, expected = parse_xml(subject, pattern)
21
+ actual.match?(expected) && expected.match?(actual)
22
+ end
23
+
24
+ private
25
+ def self.parse_xml(subject, pattern)
26
+ [Nokogiri::XML.parse(subject), Nokogiri::XML.parse(pattern)]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ require "test_xml"
2
+ require 'test_xml/test_unit/assertions'
3
+
4
+ class MiniTest::Unit::TestCase
5
+ include TestXml::TestUnit::Assertions
6
+ end
@@ -2,23 +2,29 @@ module TestXml
2
2
  module NokogiriExt
3
3
  module Node
4
4
  def match?(element, compare_value = false)
5
- if compare_value && element.text_element?
6
- equal_text?(element)
5
+ if compare_value && element.leaf?
6
+ comparable_attributes == element.comparable_attributes and equal_text?(element)
7
7
  else
8
8
  contains_elements_of?(element) &&
9
9
  element.elements.all? {|el| matches_at_least_one?(el, compare_value) }
10
10
  end
11
11
  end
12
-
12
+
13
13
  def elements
14
14
  children.collect {|node| node if node.element? }.delete_if {|node| node.nil?}
15
15
  end
16
-
17
- def text_element?
18
- children.size == 1 && children.first.text?
16
+
17
+ # Attributes of the current node.
18
+ def comparable_attributes
19
+ attributes.collect {|k,a| [k.downcase, a.value]}.sort
20
+ end
21
+
22
+ # Check if node is either childless, self-closing, or has content text.
23
+ def leaf?
24
+ children.size == 0 or (children.size == 1 && children.first.text?)
19
25
  end
20
26
 
21
- private
27
+ private
22
28
  def equal_text?(element)
23
29
  content == element.content
24
30
  end
@@ -34,7 +40,6 @@ module TestXml
34
40
  def matches_at_least_one?(element, compare_value)
35
41
  search(element.name).find { |el| el.match?(element, compare_value) }
36
42
  end
37
-
38
43
  end
39
44
  end
40
45
  end
@@ -1,5 +1,2 @@
1
+ require 'test_xml'
1
2
  require 'test_xml/spec/matchers.rb'
2
-
3
- # class Spec::Example::ExampleGroup
4
- # include TestXml::Spec
5
- # end
@@ -1,4 +1,5 @@
1
- require 'test_xml/spec/matchers/match_xml'
2
- require 'test_xml/spec/matchers/match_xml_structure'
3
- require 'test_xml/spec/matchers/exactly_match_xml_structure'
4
- require 'test_xml/spec/matchers/exactly_match_xml'
1
+ require 'test_xml/matcher_methods'
2
+ require 'test_xml/spec/matchers/contain_xml'
3
+ require 'test_xml/spec/matchers/contain_xml_structure'
4
+ require 'test_xml/spec/matchers/equal_xml_structure'
5
+ require 'test_xml/spec/matchers/equal_xml'
@@ -1,11 +1,6 @@
1
- Spec::Matchers.define :match_xml do |expected|
1
+ RSpec::Matchers.define :contain_xml do |expected|
2
2
  match do |actual|
3
- subject = Nokogiri::XML::Document.parse(actual)
4
- pattern = Nokogiri::XML::Document.parse(expected)
5
-
6
- compare_values = true
7
-
8
- subject.match?(pattern, compare_values)
3
+ TestXml::MatcherMethods.xml_contain(actual, expected)
9
4
  end
10
5
 
11
6
  failure_message_for_should do |actual|
@@ -1,9 +1,6 @@
1
- Spec::Matchers.define :match_xml_structure do |expected|
1
+ RSpec::Matchers.define :contain_xml_structure do |expected|
2
2
  match do |actual|
3
- subject = Nokogiri::XML::Document.parse(actual)
4
- pattern = Nokogiri::XML::Document.parse(expected)
5
-
6
- subject.match?(pattern)
3
+ TestXml::MatcherMethods.xml_structure_contain(actual, expected)
7
4
  end
8
5
 
9
6
  failure_message_for_should do |actual|
@@ -1,11 +1,6 @@
1
- Spec::Matchers.define :exactly_match_xml do |expected|
1
+ RSpec::Matchers.define :equal_xml do |expected|
2
2
  match do |actual|
3
- subject = Nokogiri::XML::Document.parse(actual)
4
- pattern = Nokogiri::XML::Document.parse(expected)
5
-
6
- compare_values = true
7
-
8
- subject.match?(pattern, compare_values) && pattern.match?(subject, compare_values)
3
+ TestXml::MatcherMethods.xml_equal(actual, expected)
9
4
  end
10
5
 
11
6
  failure_message_for_should do |actual|
@@ -1,8 +1,6 @@
1
- Spec::Matchers.define :exactly_match_xml_structure do |expected|
1
+ RSpec::Matchers.define :equal_xml_structure do |expected|
2
2
  match do |actual|
3
- subject = Nokogiri::XML::Document.parse(actual)
4
- pattern = Nokogiri::XML::Document.parse(expected)
5
- subject.match?(pattern) && pattern.match?(subject)
3
+ TestXml::MatcherMethods.xml_structure_equal(actual, expected)
6
4
  end
7
5
 
8
6
  failure_message_for_should do |actual|
@@ -1,3 +1,5 @@
1
+ require "test/unit"
2
+ require "test_xml"
1
3
  require 'test_xml/test_unit/assertions'
2
4
 
3
5
  class Test::Unit::TestCase
@@ -1,53 +1,50 @@
1
+ require 'test_xml/matcher_methods'
2
+
1
3
  module TestXml
2
4
  module TestUnit
3
5
  module Assertions
4
- def self.assertions_for(name, options)
5
- define_method("assert_#{name}") do |subject, &block|
6
- pattern = block.call
7
-
8
- actual = Nokogiri::XML.parse(subject)
9
- expected = Nokogiri::XML.parse(pattern)
10
6
 
7
+ def self.assertions_for(name, options)
8
+ define_method("assert_#{name}") do |subject, pattern|
11
9
  full_message = options[:message_for_should].gsub(/\<pattern\>/, pattern).gsub(/\<subject\>/, subject)
12
10
 
13
- assert_block(full_message) do
14
- options[:matcher].call(actual, expected)
15
- end
11
+ correct_assert(MatcherMethods.send(name, subject, pattern), full_message)
16
12
  end
17
13
 
18
- define_method("assert_not_#{name}") do |subject, &block|
19
- pattern = block.call
20
-
21
- actual = Nokogiri::XML.parse(subject)
22
- expected = Nokogiri::XML.parse(pattern)
23
-
14
+ define_method("assert_not_#{name}") do |subject, pattern|
24
15
  full_message = options[:message_for_should_not].gsub(/\<pattern\>/, pattern).gsub(/\<subject\>/, subject)
25
16
 
26
- assert_block(full_message) do
27
- !options[:matcher].call(actual, expected)
28
- end
17
+ correct_assert(!MatcherMethods.send(name, subject, pattern), full_message)
29
18
  end
30
19
  end
20
+
21
+
22
+ assertions_for :xml_contain,
23
+ :message_for_should => "the xml:\n<subject>\nshould contain xml:\n<pattern>",
24
+ :message_for_should_not => "the xml:\n<subject>\nshould not contain xml:\n<pattern> but it does"
31
25
 
32
- assertions_for :match_xml,
33
- :message_for_should => "the xml:\n<subject>\nshould match xml:\n<pattern>",
34
- :message_for_should_not => "the xml:\n<subject>\nshould not match xml:\n<pattern> but it does",
35
- :matcher => Proc.new {|actual, expected| actual.match?(expected, true)}
36
-
37
- assertions_for :exactly_match_xml,
26
+ assertions_for :xml_equal,
38
27
  :message_for_should => "the xml:\n<subject>\nshould exactly match xml:\n<pattern>",
39
- :message_for_should_not => "the xml:\n<subject>\nshould not exactly match xml:\n<pattern> but it does",
40
- :matcher => Proc.new {|actual, expected| actual.match?(expected, true) && expected.match?(actual, true) }
28
+ :message_for_should_not => "the xml:\n<subject>\nshould not exactly match xml:\n<pattern> but it does"
41
29
 
42
- assertions_for :match_xml_structure,
30
+ assertions_for :xml_structure_contain,
43
31
  :message_for_should => "the xml:\n<subject>\nshould match xml structure:\n<pattern>",
44
- :message_for_should_not => "the xml:\n<subject>\nshould not match xml structure:\n<pattern> but it does",
45
- :matcher => Proc.new {|actual, expected| actual.match?(expected)}
32
+ :message_for_should_not => "the xml:\n<subject>\nshould not match xml structure:\n<pattern> but it does"
46
33
 
47
- assertions_for :exactly_match_xml_structure,
34
+ assertions_for :xml_structure_equal,
48
35
  :message_for_should => "the xml:\n<subject>\nshould exactly match xml structure:\n<pattern>",
49
- :message_for_should_not => "the xml:\n<subject>\nshould not exactly match xml structure:\n<pattern> but it does",
50
- :matcher => Proc.new {|actual, expected| actual.match?(expected) && expected.match?(actual) }
36
+ :message_for_should_not => "the xml:\n<subject>\nshould not exactly match xml structure:\n<pattern> but it does"
37
+
38
+ private
39
+ def correct_assert(boolean, message)
40
+ if RUBY_VERSION =~ /1.9.2/ or defined?(MiniTest)
41
+ assert(boolean, message)
42
+ else
43
+ assert_block(message) do
44
+ boolean
45
+ end
46
+ end
47
+ end
51
48
  end
52
49
  end
53
50
  end