Giter Club home page Giter Club logo

Comments (11)

italojs avatar italojs commented on June 23, 2024

I think in that way we are changing an apple by pear, it's the quit same thing of write my own test, I dont see so much value in use it, buuuuuut the ideia/proposal is awesome and I think we could to go beyond.

Once we have the entity's validation and we could to use it as metadata, we could to auto generate the basic usacase tests based on entitiy's validation. e.g:

entity('Product', {
        id: id(Number),
        name: field(String, { 
                       validation: { 
                                 length: { minimum: 6 } ,
                                 contains: { notAllowed: "hello world" } 
          } } )
    })
const { CreateProduct } = require('./usecases/createProduct')

spec(CreateProduct, {

    'Successful create a simple product': scenario({
        description: 'Try to create a product with just a valid name.',

        request: {
            name: 'A simple product'
        },

        user: () =>
            ({ canCreateProduct: true }),

        injection: () =>
            ({ ProductRepo: { save: () => { id: 1 } } })

         'my super specific scenario': check((ret) => {
            assert.ok(ret.product.name.lenght/2 * 8  !== 10000)
        }),
    }),

terminal output:

Runned the tests:

⚙️ Happy Path: true
- Successful create a simple product
🟢  must to have an id
🟢  must to have a valid name
🟢  name do not have "hello world"

⚙️  Happy Path: false
- Unsuccessful create a simple product
🟢  must to not return id for invalid entity
🟢  must to return an Err XXX if invalid name
🟢  must to return an Err YYY  if name contains "hello world"

⚙️  Specific scenarios:
🟢  my super specific scenario

look, we have 6 tests auto-generated by herbs, I think this way we bring the Herbs idea of provide the things based on metadatas.

Other interesting scenario is when the usecase handle multiples entities, I could to generate test for all entities and combine all possible tests between then.

For now, I dont know how we could to know what is all entities the usecase handle, but I think this is the way.

from herbs.

jhomarolo avatar jhomarolo commented on June 23, 2024

@dalssoft First of all, I'd like to say that I think the idea is quite interesting, tests are really one of the things herbs hasn't reached yet.

I have some doubts and questions about the points mentioned:

1- A glue instead of a lib

Have you considered using a test library instead of creating your own? It seems to me that we can build this on top of something consolidated, like a connector (for example mocha). This would give us several benefits such as robustness, code coverage, reporting, shortening the learning curve, and not having to go to a part that herbs don't master.

2 - About Given / When / Then

How about we encapsulate the "3 magic words" in variables, just like we do with steps? I think it would be more readable, more reusable (for multiple entries), and also more declarative.

Example:

spec(ChangeItemPosition, {

    'Successful change item position': scenario({
        description: 'Try to change the item position in a list with a valid position.',

        given = given(async (ctx) => { 
        request: {
            itemId: 1,
            position: 10
        },

        user: () =>
            ({ canChangePosition: true }),

        injection: () =>
        ({
            ListRepo: { find: (id) => ({ id, items: [] }) },
            ItemRepo: { save: () => ({ position: 10 }) }
        })
        )} 

        when = when (async (ctx) => { 
         const uc = usecase(given.injection)
          const hasAccess = await uc.authorize(given.user)
          const response = await uc.run(given.request)
       )}

        then = then (async (ctx) => { 
        'Item position must have been changed and saved in the repository': check((ret) => {
            assert.ok(ret.item.position === 10)
        }),

        'Item position must be in a valid range': check((ret) => {
            assert.ok(ret.item.position >= 0)
            assert.ok(ret.item.position <= 20)
        })

    })
})

Here I wouldn't make the when transparent, because that way you plaster the way the developer uses the code. For example, not every use case is authorized. Another point is that if you encapsulate the given, then and when at the metadata level, this can be very rich for the shelf and for the herbarium.

3 - About spies

I think what convinces me to create a library of our own is if we could actually look deeply here.
Example: connecting the audit with the test runner or knowing exactly which step of the use case broke the test or even performing specific validations in steps. But I think we can do it with glue still (I need to study more on the subject)

4 - About self-generated tests from Entities

I really like the @italojs idea, but I believe that Entities need to have their own test files, disconnected from use cases.
In my opinion, your idea does not conflict with @dalssoft idea, they are two different initiatives that can be matured in different topics because in my view both are valid.

from herbs.

eacvortx avatar eacvortx commented on June 23, 2024

I really think that ideas is great! I can see the value of an Aloe, especially for the business specialist if we add this to analyse the structure of the project into the Shelf...

Thinking about this documentation when we have different contexts in the same Use Case, we can define different contexts with the mocha, like context or describe...

What do you think of mantain some of these labels to improve the organization of tests?

Example, an UseCase with IfelseStep with bifurcation of the complex rules can use this to improve the view when we use this into the shelf and the terminal...

from herbs.

dalssoft avatar dalssoft commented on June 23, 2024

I think in that way we are changing an apple by pear, it's the quit same thing of write my own test, I dont see so much value in use it, buuuuuut the ideia/proposal is awesome and I think we could to go beyond.

@italojs, but the point is exactly that: the tests we write today (ex: with mocha or cucumber) are not part of the domain and can't export metadata

1- A glue instead of a lib

@jhomarolo maybe. I don't see much value on the runner. I may be not giving the importance due to the problem, but I don't see the runner as the complex part of the software. The complex part is to build the DSL, like we did with gotu and buchu

2 - About Given / When / Then

@jhomarolo it is something to be explored

4 - About self-generated tests from Entities

@jhomarolo agree

Example, an UseCase with IfelseStep with bifurcation of the complex rules can use this to improve the view when we use this into the shelf and the terminal...

@eacvortx could you elaborate on that?

from herbs.

dalssoft avatar dalssoft commented on June 23, 2024

New proposed syntax.

For Use Cases:

const { CreateProduct } = require('./usecases/createProduct')

const productSpec =
    spec(CreateProduct, {

        'Successful create a simple product': scenario({
            description: 'Try to create a product with just a valid name.',
            happyPath: true,

            'Given a simple Product': given({
                request: {
                    name: 'A simple product'
                },
                user: () => ({ canCreateProduct: true }),
                injection: () => ({
                    ProductRepo: { save: () => { id: 1 } }
                }),
            }),

            'Product must be saved in the repository': check((ret) => {
                assert.ok(ret.product.id)
            }),

            'Product must have a new Id': check((ret) => {
                assert.ok(ret.product.id === 1)
            }),
        }),

        'Do not save a product with invalid name': scenario({
            description: 'Reject products with invalid names in the repository',

            'Given a invalid Product': given({
                request: { name: 'A simple product @' },
                user: () => ({ canCreateProduct: true }),
                injection: () => { },
            }),

            'Product should not be saved in the repository': check((ret) => {
                assert.ok(ret.product === null)
                assert.ok(ret.isInvalidEntityError)
            }),
        })
    })

For entities:

const { Project } = require('./entities/project')

const projectSpec =
    spec(Project, {

        'Successful create a valid Project': scenario({
            description: 'Try to create a project with just a valid name.',
            happyPath: true,

            'Given a simple Project': given(() => {
                return Project.fromJSON({
                    name: 'New project'
                })
            }),

            'When check if is valid': when((product) => {
                product.validate()
                return product
            }),

            'Must be valid': check((product) => {
                assert.ok(product.errors === {})
            }),
        }),

        // *** Custom methods ***
        'Successful generate a valid Project ID': scenario({
            description: 'Try to create a project ID based on its name.',
            happyPath: true,

            'Given a simple Project': given(() => {
                return Project.fromJSON({
                    name: 'New project'
                })
            }),

            'When generate project ID': when((product) => {
                return product.generateID()
            }),

            'Must be valid': check((ret) => {
                assert.ok(ret === 'new-project')
            }),
        }),
    })

Please, comment.

from herbs.

jhomarolo avatar jhomarolo commented on June 23, 2024

I liked the changes, especially the inclusion of reserved words. Perhaps the explicit inclusion of then also makes sense.

I'm still finding it difficult to easily enable integrations with other tools that we normally use for CI (test coverage, reports, etc.). Do you believe that we will implement these functions or at some point make integrations with third-party tools?

from herbs.

dalssoft avatar dalssoft commented on June 23, 2024

I'm still finding it difficult to easily enable integrations with other tools that we normally use for CI (test coverage, reports, etc.).

Regarding test coverage, I'm not sure, but it seems the coverage tools [1] are agnostic to the test runner.

For others tools, what problems / issues do you expect to find?

[1] https://github.com/jaydenseric/coverage-node

from herbs.

jhomarolo avatar jhomarolo commented on June 23, 2024

This feature could be an alternative to implement aloe without create a test runner: nodejs/node#42325

from herbs.

italojs avatar italojs commented on June 23, 2024

To provide a great DX and a fast learn curve, we could work with context like usecases

           'Given a simple Project': given((ctx) => {
                ctx.product  = Product.fromJSON({
                    name: 'New project'
                })
                return ctx
            }),

            'When check if is valid': when((ctx) => {
                ctx.product.validate()
                return product
            }),

            'Must be valid': check((ctx.product) => {
                assert.ok(ctx.product.errors === {})
            }),
        }),

because sometimes I could put many instances inside the ctx instead only my principal entity

from herbs.

dalssoft avatar dalssoft commented on June 23, 2024

we could work with context like usecases

@italojs on the current implementation it ends up exactly like that:

https://github.com/herbsjs/herbs-cli/blob/8862645afca06433ccd605b0e06ff1cb56cee026/src/templates/domain/useCases/tests/update.spec.ejs#L22

from herbs.

dalssoft avatar dalssoft commented on June 23, 2024

Since Aloe has already landed on herbs and CLI as beta, I'm closing this issue. Any suggestions or improvements, please use Aloe repo.

from herbs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.