test_generator 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/ext/string.rb +47 -0
- data/lib/generators/equivalence_class_generator.rb +64 -0
- data/lib/generators/unit_test_generator.rb +120 -0
- data/lib/reflector.rb +16 -0
- data/lib/templates/aspects.rb +58 -0
- data/lib/test_generator.rb +13 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e7909cf0b3c6a8fdf7e19e25ffd386e52ffdbce97924609d33d7c9b26046d6f9
|
4
|
+
data.tar.gz: 2a103ab5ac36e823cda0bd6d312523440765c8d0983a92d194e16e08e9ab3a0c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5421450d717d4fe6044cb9d2dbf79ab389e1a16322123d4c40fec91fe49e19155053acacf566beaf4929fd6e187f1a1ffc570d059551218476ff56a6dceac4a8
|
7
|
+
data.tar.gz: bbf3b9d80c25c4c69a85d991cb092401b1f415bf841fa9e56058bcafcb52367a661754e9cdf2c9f9482d25535e4d083897839e9d5c47bff971ace4f34896fbd6
|
data/lib/ext/string.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class String
|
2
|
+
# strings de cada classe de equivalência para testes
|
3
|
+
INT_STRING = "3"
|
4
|
+
EMAIL_STRING = "genaina@email.com"
|
5
|
+
FLOAT_STRING = "3.14"
|
6
|
+
PHONE_STRING = "(61) 98999-9999"
|
7
|
+
DATE_STRING = "12/01/1997"
|
8
|
+
|
9
|
+
CUSTOM_METHODS = %w(is_i? is_email? is_float? is_phone? is_date?)
|
10
|
+
|
11
|
+
EQUIVALENCE_CLASSES = {
|
12
|
+
"is_i?" => "INTEGER",
|
13
|
+
"is_email?" => "EMAIL",
|
14
|
+
"is_float?" => "FLOAT",
|
15
|
+
"is_phone?" => "PHONE",
|
16
|
+
"is_date?" => "DATE",
|
17
|
+
}
|
18
|
+
|
19
|
+
STRINGS_EQUIVALENCE_CLASSES = {
|
20
|
+
"is_i?" => String::INT_STRING,
|
21
|
+
"is_email?" => String::EMAIL_STRING,
|
22
|
+
"is_float?" => String::FLOAT_STRING,
|
23
|
+
"is_phone?" => String::PHONE_STRING,
|
24
|
+
"is_date?" => String::DATE_STRING,
|
25
|
+
}
|
26
|
+
|
27
|
+
def is_i?
|
28
|
+
/\A[-+]?\d+\z/ === self
|
29
|
+
end
|
30
|
+
|
31
|
+
def is_email?
|
32
|
+
/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i === self
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_float?
|
36
|
+
self.to_f.to_s === self
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_phone?
|
40
|
+
/^\([1-9]{2}\) (?:[2-8]|9[1-9])[0-9]{3}\-[0-9]{4}$/ === self ||
|
41
|
+
/^\([1-9]{2}\)(?:[2-8]|9[1-9])[0-9]{3}\-[0-9]{4}$/ === self
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_date?
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
class EquivalenceClassGenerator < Rails::Generators::Base
|
3
|
+
def create_equivalence_class_tests
|
4
|
+
require 'json'
|
5
|
+
require 'reflector'
|
6
|
+
class_name = args[0]
|
7
|
+
file_name = class_name.downcase
|
8
|
+
puts "criando testes unitarios para #{class_name}..."
|
9
|
+
is_controller = /.*Controller$/.match?(class_name)
|
10
|
+
class_type = "model"
|
11
|
+
|
12
|
+
template = %Q{require 'rails_helper'
|
13
|
+
|
14
|
+
RSpec.describe #{class_name}, :type => :#{class_type} do
|
15
|
+
}
|
16
|
+
equivalence_class_counter = {}
|
17
|
+
File.readlines("#{Rails.root}/tmp/#{class_name}.rb").each do |line|
|
18
|
+
json_string = JSON.parse(line.strip)
|
19
|
+
puts "\nReflecting..."
|
20
|
+
reflector = Reflect::Reflector.new
|
21
|
+
klass = json_string["klass"]
|
22
|
+
meth = json_string["method"]
|
23
|
+
cs = json_string["current_state"]
|
24
|
+
args = json_string["args"]
|
25
|
+
class_and_method_name = "#{klass}::#{meth}"
|
26
|
+
|
27
|
+
equivalence_class_counter[meth] ||= {}
|
28
|
+
args.each do |arg|
|
29
|
+
String::CUSTOM_METHODS.each do |equivalence_class_method|
|
30
|
+
respond_to_eq_class = arg.send(equivalence_class_method) # testa pra ver se responde à alguma classe de equivalencia
|
31
|
+
if respond_to_eq_class # se responder à classe, adiciona 1 ao contador daquela classe
|
32
|
+
if equivalence_class_counter[meth][equivalence_class_method].nil?
|
33
|
+
equivalence_class_counter[meth][equivalence_class_method] = 1
|
34
|
+
else
|
35
|
+
equivalence_class_counter[meth][equivalence_class_method] += 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
equivalence_class_counter.each do |method,stats| # pega o hash com os métodos e as estatísticas de cada
|
44
|
+
probabily_class = stats.max_by{|k,v| v}
|
45
|
+
template_aux = %Q{
|
46
|
+
describe '##{method}_equivalence_class' do
|
47
|
+
# #{probabily_class.last} entries with this class
|
48
|
+
it "arguments should belong to #{String::EQUIVALENCE_CLASSES[probabily_class.first]} equivalence class" do
|
49
|
+
expect(#{class_name.capitalize}).to receive(:#{method}).with("#{String::STRINGS_EQUIVALENCE_CLASSES[probabily_class.first]}")
|
50
|
+
User.find_by_email_address("#{String::STRINGS_EQUIVALENCE_CLASSES[probabily_class.first]}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
}
|
54
|
+
template.concat(template_aux)
|
55
|
+
end
|
56
|
+
puts equivalence_class_counter
|
57
|
+
|
58
|
+
template.concat(%Q{
|
59
|
+
end
|
60
|
+
})
|
61
|
+
|
62
|
+
create_file "spec/#{class_type}s/#{file_name}_equiv_spec.rb", template
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
class UnitTestGenerator < Rails::Generators::Base
|
3
|
+
def create_unit_tests
|
4
|
+
require 'json'
|
5
|
+
require 'reflector'
|
6
|
+
class_name = args[0]
|
7
|
+
file_name = class_name.downcase
|
8
|
+
puts "criando testes unitarios para #{class_name}..."
|
9
|
+
is_controller = /.*Controller$/.match?(class_name)
|
10
|
+
class_type = "model"
|
11
|
+
first_line = File.open("#{Rails.root}/tmp/#{class_name}.rb", &:readline)
|
12
|
+
sample_object = JSON.parse(first_line)["current_state"]
|
13
|
+
|
14
|
+
executed_methods = []
|
15
|
+
executed_arguments = {}
|
16
|
+
if is_controller
|
17
|
+
class_type = "controller"
|
18
|
+
template = %Q{require 'rails_helper'
|
19
|
+
|
20
|
+
RSpec.describe #{class_name}, :type => :#{class_type} do
|
21
|
+
}
|
22
|
+
File.readlines("#{Rails.root}/tmp/#{class_name}.rb").each do |line|
|
23
|
+
json_string = JSON.parse(line.strip)
|
24
|
+
puts "\nReflecting..."
|
25
|
+
reflector = Reflect::Reflector.new
|
26
|
+
klass = json_string["klass"]
|
27
|
+
meth = json_string["method"]
|
28
|
+
cs = json_string["current_state"]
|
29
|
+
args = json_string["args"]
|
30
|
+
class_and_method_name = "#{klass}::#{meth}"
|
31
|
+
if executed_methods.include?(class_and_method_name)
|
32
|
+
if executed_arguments[class_and_method_name.to_sym].include?(args)
|
33
|
+
# do nothing, same test
|
34
|
+
else
|
35
|
+
# same test with other arguments
|
36
|
+
executed_arguments[class_and_method_name.to_sym].push(args)
|
37
|
+
end
|
38
|
+
else # other test for other method
|
39
|
+
executed_methods.push(class_and_method_name)
|
40
|
+
executed_arguments[class_and_method_name.to_sym] = []
|
41
|
+
puts "Executando #{klass}::#{meth} com argumentos #{args} no objeto #{sample_object}"
|
42
|
+
reflection = reflector.reflect(klass, meth, sample_object, args)
|
43
|
+
puts "Resultado: #{reflection}"
|
44
|
+
print "\n"
|
45
|
+
|
46
|
+
template_aux = %Q{
|
47
|
+
describe 'GET #{meth}' do
|
48
|
+
it 'returns a successful response' do
|
49
|
+
get :#{meth}
|
50
|
+
expect(response).to be_successful
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'renders the #{meth} template' do
|
54
|
+
get :#{meth}
|
55
|
+
expect(response).to render_template("#{meth}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
}
|
59
|
+
template.concat(template_aux)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
template.concat(%Q{
|
64
|
+
end
|
65
|
+
})
|
66
|
+
else
|
67
|
+
template = %Q{require 'rails_helper'
|
68
|
+
|
69
|
+
RSpec.describe #{class_name}, :type => :#{class_type} do
|
70
|
+
let(:#{file_name}) { #{class_name}.new(#{sample_object}) }
|
71
|
+
|
72
|
+
it "is valid with valid attributes" do
|
73
|
+
expect(#{file_name}).to be_valid
|
74
|
+
end
|
75
|
+
}
|
76
|
+
File.readlines("#{Rails.root}/tmp/#{class_name}.rb").each do |line|
|
77
|
+
json_string = JSON.parse(line.strip)
|
78
|
+
puts "\nReflecting..."
|
79
|
+
reflector = Reflect::Reflector.new
|
80
|
+
klass = json_string["klass"]
|
81
|
+
meth = json_string["method"]
|
82
|
+
cs = json_string["current_state"]
|
83
|
+
args = json_string["args"]
|
84
|
+
class_and_method_name = "#{klass}::#{meth}"
|
85
|
+
if executed_methods.include?(class_and_method_name)
|
86
|
+
if executed_arguments[class_and_method_name.to_sym].include?(args)
|
87
|
+
# do nothing, same test
|
88
|
+
else
|
89
|
+
# same test with other arguments
|
90
|
+
executed_arguments[class_and_method_name.to_sym].push(args)
|
91
|
+
end
|
92
|
+
else # other test for other method
|
93
|
+
executed_methods.push(class_and_method_name)
|
94
|
+
executed_arguments[class_and_method_name.to_sym] = []
|
95
|
+
puts "Executando #{klass}::#{meth} com argumentos #{args} no objeto #{sample_object}"
|
96
|
+
reflection = reflector.reflect(klass, meth, sample_object, args)
|
97
|
+
puts "Resultado: #{reflection}"
|
98
|
+
print "\n"
|
99
|
+
|
100
|
+
template_aux = %Q{
|
101
|
+
describe '##{meth}' do
|
102
|
+
it "should return valid string for method #{meth}" do
|
103
|
+
expect(#{class_name.downcase}.#{meth}(#{args.join(', ')})).to eq "#{reflection}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
}
|
107
|
+
template.concat(template_aux)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
template.concat(%Q{
|
112
|
+
end
|
113
|
+
})
|
114
|
+
end
|
115
|
+
|
116
|
+
create_file "spec/#{class_type}s/#{file_name.sub('controller', '_controller')}_spec.rb", template
|
117
|
+
|
118
|
+
puts "Testes criados."
|
119
|
+
end
|
120
|
+
end
|
data/lib/reflector.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Reflect
|
2
|
+
class Reflector
|
3
|
+
def reflect(klass, method, attributes, args)
|
4
|
+
if attributes.nil?
|
5
|
+
@instance = Object.const_get(klass).new
|
6
|
+
else
|
7
|
+
@instance = Object.const_get(klass).new(attributes)
|
8
|
+
end
|
9
|
+
if Object.const_get(klass).respond_to?(method) # class method
|
10
|
+
Object.const_get(klass).send(method, *args)
|
11
|
+
else
|
12
|
+
@instance.send(method, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'aquarium'
|
2
|
+
include Aquarium::Aspects
|
3
|
+
|
4
|
+
# Load Rails constants
|
5
|
+
Rails.application.eager_load!
|
6
|
+
|
7
|
+
# Get Rails models and controllers classes
|
8
|
+
controllers = ApplicationController.subclasses
|
9
|
+
models = ApplicationRecord.subclasses
|
10
|
+
|
11
|
+
puts "Aspects initialized"
|
12
|
+
|
13
|
+
Aspect.new(:around,
|
14
|
+
calls_to: :all_methods,
|
15
|
+
for_types: models + controllers,
|
16
|
+
method_options: [:exclude_ancestor_methods, :class]) do |jp, obj, *args|
|
17
|
+
begin
|
18
|
+
# Get class
|
19
|
+
klass = jp.target_type.name.constantize
|
20
|
+
# puts klass
|
21
|
+
|
22
|
+
# List all klass public instance methods
|
23
|
+
if models.include? klass
|
24
|
+
public_instance_methods = (klass.public_instance_methods - Object.public_instance_methods).sort
|
25
|
+
# puts public_instance_methods
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get method
|
29
|
+
method = jp.method_name.to_sym
|
30
|
+
# puts method
|
31
|
+
|
32
|
+
# Get object current state
|
33
|
+
if models.include? klass
|
34
|
+
if obj.class == Class
|
35
|
+
else
|
36
|
+
current_state = obj.attributes
|
37
|
+
end
|
38
|
+
# puts current_state
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create temp file
|
42
|
+
file_name ="#{Rails.root}/tmp/#{klass.to_s}.rb"
|
43
|
+
|
44
|
+
file = File.new(file_name, 'a')
|
45
|
+
|
46
|
+
str = "{ \"klass\": \"#{klass}\", \"method\": \"#{method}\", \"args\": #{args.inspect}, \"current_state\": #{current_state.to_json} }"
|
47
|
+
|
48
|
+
unless File.open(file_name).each_line.any? { |line| line.include?(str)}
|
49
|
+
file.puts str
|
50
|
+
end
|
51
|
+
|
52
|
+
jp.proceed
|
53
|
+
ensure
|
54
|
+
if file
|
55
|
+
file.close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module TestGenerator
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
desc "Creates a aspects initializer file."
|
6
|
+
def create_aspect_initialize_file
|
7
|
+
template = File.read('./templates/aspects.rb')
|
8
|
+
create_file "config/initializers/aspects.rb", template
|
9
|
+
|
10
|
+
puts "Aspects Initializer created."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: test_generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Marques
|
8
|
+
- Rafael Fernandes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2020-07-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 3.2.0
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 3.2.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: cucumber-rails
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec-rails
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: aquarium
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
description: This gem will track everything users do in the system and map it into
|
71
|
+
controllers and model methods beeing called, and generate tests for them
|
72
|
+
email:
|
73
|
+
- nnmarques97@gmail.com
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- lib/ext/string.rb
|
79
|
+
- lib/generators/equivalence_class_generator.rb
|
80
|
+
- lib/generators/unit_test_generator.rb
|
81
|
+
- lib/reflector.rb
|
82
|
+
- lib/templates/aspects.rb
|
83
|
+
- lib/test_generator.rb
|
84
|
+
homepage: https://github.com/NickNish09/TestGenerator
|
85
|
+
licenses: []
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubygems_version: 3.0.6
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: Auto generate tests based on system usage and BDD.
|
106
|
+
test_files: []
|