test_generator 1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|