Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean Up and Dry Tests #344

Merged
merged 7 commits into from Nov 1, 2017
Merged

Clean Up and Dry Tests #344

merged 7 commits into from Nov 1, 2017

Conversation

eliasjpr
Copy link
Contributor

Description of the Change

As the framework grows having a clean and expressive test suite is very important for those who are currently working on the project and new people that want to contribute.

This PR is a WORK IN PROGRESS to clean up and structure the test using the Arrange, Act, Assert Annihilate pattern with only one action and one assertion.

Alternate Designs

  • Currently the test suite is just testing each class part of the Amber Framework maybe it would be a good idea to create 2 directories for integrations, unit tests

Benefits

With the work done it will make it very easy to read and maintain the test suite

Possible Drawbacks

  • Maybe there is a better design outther

@eliasjpr eliasjpr added the WIP label Oct 30, 2017
@eliasjpr eliasjpr requested review from a team October 30, 2017 20:20

CONT
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crystal will create whitespace based on the closing CONT, so you can do:

module CLIFixtures
  def expected_controller
    <<-CONT
    class AnimalController < ApplicationController
      def add
        render("add.slang")
      end

      def list
        render("list.slang")
      end

      def remove
        render("remove.slang")
      end
    end
    CONT
  end
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was confused about this, fixing it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing CONT should align with class and the last end

@marksiemers
Copy link
Contributor

@eliasjpr Thanks for your work on this.

I like a lot of the refactoring so far (particularly scaffold_app)

My main concern is moving should statements into helpers. Crystal's Spec definitely has taken cues from RSpec, and there, the convention is to have should statements directly in an it block. (Well in RSpec it is expect now).

@eliasjpr
Copy link
Contributor Author

I agree when having 1 assertion line, but when there is multiple line attempting to assert related expectations we should have them in a composed assert method, this makes it very reusable, readable and follow the one assert rule. IMHO

An example of this is when asserting if the encryption files exists after encrypting.

File.exists?("config/environments/#{enc_file}").should be_true
File.read(enc_key).size.should eq 44

@marksiemers
Copy link
Contributor

marksiemers commented Oct 30, 2017

I think "Assert" in the AAA pattern is roughly equal to should in Spec, if you move two shoulds into a helper, IMHO it is just hiding that there are two asserts.

I think the idea behind the one assertion per test, is to make each test (it) statement as granular as possible.

Using this spec file as a starting point

describe MainCommand::Encrypt do
  context "application structure" do
    it "creates amber directory structure" do
      scaffold_app(TESTING_APP)
      MainCommand.run ["encrypt", "test"]
      assert_encrypted_files_exists?(".test.enc", ".amber_secret_key")
      cleanup
    end
  end
end

The it statement seems broad, and does not match what the assertion is actually checking.

I would like to see that our goal is to have each it only execute one should (directly or indirectly). For example, I find the following code more readable and I have a better understanding of what amber encrypt test should do:

describe MainCommand::Encrypt do
  begin
    scaffold_app(TESTING_APP)
    arg = "test"
    MainCommand.run ["encrypt", arg]

    it "should create an hidden .[arg].enc file" do
      File.exists?("config/environments/.#{arg}.enc").should be_true
    end

    it "should create a 44 character secret key in .amber_secret_key" do
      File.read(".amber_secret_key").size.should eq 44
    end

  ensure
    cleanup
  end
end

I know it isn't always practical to have a 1:1 it to should ratio, but I think using it as a guide can lead to more declarative and descriptive tests.

@eliasjpr
Copy link
Contributor Author

Thats what I am looking for! Thanks @marksiemers

@marksiemers
Copy link
Contributor

It isn't bad practice to setup descriptions for all your known requirements right away:

module Amber::CLI
  describe MainCommand::Perform do
    it "performs a tasks via command line" {} # `it` requires a block

    it "performs a tasks via command line alias" {}

    it "shows task description" {}
  end
end

@eliasjpr eliasjpr force-pushed the ep/clean-tests branch 3 times, most recently from 070aac6 to 55e81b4 Compare October 31, 2017 00:41
Copy link
Contributor

@marksiemers marksiemers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eliasjpr - Overall, this is great. The organization into helpers and fixtures looks really good.

I have some inline comments about renaming/restructuring the outlines of some of the specs, but again, this mostly looks great.


context "when scaffolding an Amber app" do
scaffold_app(TESTING_APP)
MainCommand.run ["generate", "scaffold", "Animal", "name:string"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line shouldn't be needed to test a shards build - did we just want something in there?

If we want a more complete test, it should be structured something like this:

context "scaffolding an Amber app"  
  assert that it builds
  test scaffold generator (in a describe block)
  test controller generator (in a describe block)
  test model generator (in a describe block)
  ...test each generator...
  assert that it still builds
  cleanup
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Practically speaking, we may not want two builds, until the shard downloading thing is optimized one way or another.

It might be better to test the shard building at the end - will it build after all the generators have been run, or did any of them introduce a compile time error?

cleanup
end

context "when generating controllers" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantically, I would say we are in the context of "scaffolding and amber app" and this should be describe "amber generate controller"

MainCommand.run ["generate", "controller", controller] | options

it "generates controller with correct verbs and actions" do
File.read("./src/controllers/#{controller.downcase}_controller.cr").should eq expected_controller
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line and line 25 are coupling this code with wherever expected_controller is defined. I would say choose one place and have both controller = "Animal" and whatever is in the definition of expected_controller. I think the helper or the fixture is the better place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an example of how I approached it, see here: 3220d13

And the helper here: https://github.com/marksiemers/amber/blob/3220d1312608f53ca486b8f5a668219870c19b57/spec/amber/cli/templates/migration_spec_helper.cr

All the decisions about names are in the helper - so they are easier to keep in sync.

end

def layout_with_template
%(<html>\n <body>\n <h1>Hello World</h1>\n<p>I am glad you came</p>\n </body>\n</html>)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for this not to use a heredoc like the others?

Amber::CLI::Spec.cleanup
end
describe MainCommand::New do
context "application structure" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this describe "amber new #{TESTING_APP}"

end

context "template" do
cleanup
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be necessary?

HTML

TestController.new(context).render_with_csrf.should eq html_output
TestController.new(context).render_with_csrf.should eq csrf_form
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this looks so much better with the refactor, nice work.

end
end

CONT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as you move the closing CONT over, you can safely indent the string.

include CookieHelper
include RouterHelper
include WebsocketsHelper
include ValidationsHelper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this organization.

Elias J. Perez added 3 commits October 31, 2017 18:54
This organizes and cleans up and DRY the CLI specs making it more
readable and cohesive.
@eliasjpr eliasjpr force-pushed the ep/clean-tests branch 4 times, most recently from a85af50 to 0b6caad Compare November 1, 2017 15:28
@eliasjpr eliasjpr changed the title [WIP] Clean Up and Dry Tests Clean Up and Dry Tests Nov 1, 2017
@eliasjpr eliasjpr removed the WIP label Nov 1, 2017
Amber::CLI::Spec.cleanup
end
end
describe MainCommand::Encrypt do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any opinion on having this be describe "amber encrypt" do ?

Copy link
Contributor

@marksiemers marksiemers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See inline comments, the name changes for the describe/context blocks are optional.

If the assert methods are not being used anymore, they should be removed.


`shards build`
module Amber::CLI
describe MainCommand::Generate do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here - we could have describe "amber generate" do and remove the context below.

Amber::CLI::Spec.amber_yml["language"].should eq "slang"
File.read("#{TESTING_APP}/.amber_secret_key").size.should eq 44
Amber::CLI::Spec.cleanup
describe MainCommand::New do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here, describe "amber new #{TESTING_APP}" do and remove the context below.

dirs(TESTING_APP).sort.should eq dirs(APP_TEMPLATE_PATH).sort
end

describe "-m granite (Granite ORM)" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this context but it isn't a deal-breaker.

Amber::CLI::Spec.db_yml["pg"].should_not be_nil
db_url = Amber::CLI::Spec.db_yml["pg"]["database"].as_s
db_url.should_not be_nil
describe "-m crecto (Crecto Repo)" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing, context

def assert_encrypted_files_exists?(enc_file, enc_key)
File.exists?("config/environments/#{enc_file}").should be_true
File.read(enc_key).size.should eq 44
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these still needed?

Copy link
Member

@drujensen drujensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be a lot cleaner but didn't spend a ton of time reviewing since its such a large PR.

@eliasjpr eliasjpr merged commit 5649619 into master Nov 1, 2017
@eliasjpr eliasjpr deleted the ep/clean-tests branch November 2, 2017 18:55
elorest pushed a commit that referenced this pull request Nov 17, 2017
* Organize Factories into Fixtures

* Organizes Helpers into submodules

* Cleans up the CLI Commands Specs

This organizes and cleans up and DRY the CLI specs making it more
readable and cohesive.

* Updates

* fixup! Organize Factories into Fixtures

* fixup! Organize Factories into Fixtures

* fixup! Organize Factories into Fixtures
elorest pushed a commit that referenced this pull request Nov 17, 2017
* Organize Factories into Fixtures

* Organizes Helpers into submodules

* Cleans up the CLI Commands Specs

This organizes and cleans up and DRY the CLI specs making it more
readable and cohesive.

* Updates

* fixup! Organize Factories into Fixtures

* fixup! Organize Factories into Fixtures

* fixup! Organize Factories into Fixtures


Former-commit-id: b6f0459
@faustinoaq faustinoaq added this to Done in Framework 2018 May 5, 2018
@faustinoaq faustinoaq removed this from Done in Framework 2018 Jun 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

4 participants