Duplicate Node.js `assert` statements in spec` expect`

Unlike non-approved code with custom developer-compatible checks,

class Some { constructor(arg) { if (Array.isArray(arg) && arg[0] === 'foo') this.foobar = arg.concat('bar').join(''); else console.error('Bad Some constructor arg'); } } 

The code currently checked is heavily packed with Node assert with reasonably significant message arguments:

 class Some { constructor(arg) { assert.deepEqual(arg, ['foo'], 'Some constructor arg'); this.foobar = arg.concat('bar').join(''); } } 

Approval exists for

  • save the code in the same place and readable
  • provide meaningful feedback on misuse with the call stack
  • prevent function execution and do not propagate the error further
  • output an error and leave the error handling to the caller

The current specification may look like this:

 it('...', () => { let some = new Some(['foo']); expect(some).to... 

And it will pass - the desired use is stated in the spec, the unwanted use that it claimed in the tested code.

To partially overlap code statements, it can even be

 it('...', () => { const { AssertionError } = require('assert'); let some = new Some(['foo']); expect(some).to... expect(() => new Some(['bar']).to.throw(AssertionError); 

So, we basically assume that half of the test task has already been completed in the code itself using assert and skip the details ( to.not.throw and matching message AssertionError).

The above example uses Mocha + Chai, but the same applies to Jasmine.

  • Should application statements be treated like any other lines of code and doubled with statements about specifications (in order to throw, not throw, AssertionError message correspondence), what are the consequences of accepting a shortcut?

  • Is it possible to test coverage tools (Istanbul) with assert statements in the application code in addition to expect ?

  • Can runners be confused by the fact that it was an application, not a statement of the specification that caused the error?

Some examples of successful open source JS projects that prove or disprove the claim to claim statements in practice may also be helpful.

+6
source share
3 answers

Should application statements be considered any other lines of code and double with specifications statements (throw, not throw, AssertionError collation), what are the consequences of accepting a shortcut?

Claims about applications should inform the developer about the incorrect use of a certain piece of code, ideally they will never happen in production. If this happens, they serve as a tool for identifying what went wrong, just like a standard error. But ideally, they are the first line of defense during development, and they should only happen. (therefore, this is one of the reasons why in some languages ​​you can turn off statements for runtime all together)

If you are writing some class that uses statements to make sure that the input parameters are confirmed or the program is not used inconsistently, then it certainly makes sense to add this logic to unit tests. If you are going to change the statements at some point, you want to check that you are not breaking other people's code.

Can testing coverage tools (Istanbul) take into account statements in the application code in addition to the expectation?

Yes. If you set up a unit test that will lead to approval and then capture it in chai, then that code will appear in your coverage report. This is no different from any other code if I misunderstand your question.

Can runners be confused by the fact that it was an application, not a statement of the specification that caused the error?

When you write assertions using the assert module, it will throw an AssertionError . This is the AssertionError class from the assert module. When chai throws an error, it also throws an AssertionError , but it will be a completely different class coming from the chai module, they only share the name. Thus, there should not be any confusion as to where the statements come from.
Usually you do not commit statements in test code in all try / catch constructs, so this really should not be a problem.

Usually statements test much less complex states than unit test. But where statements and unit tests should end, it is not formally defined. Additional Information:

https://softwareengineering.stackexchange.com/questions/18288/are-asserts-or-unit-tests-more-important

+1
source

Should application statements be considered any other lines of code and double with specifications statements (throw, not throw, AssertionError collation), what are the consequences of accepting a shortcut?

I would not recommend this. This is similar to testing a test: although it is technically possible, you usually do not do this because it is not worth the cost.

Can testing coverage tools (Istanbul) take into account statements in the application code in addition to the expectation?

What behavior would you like to get? With unit test, it’s perfectly clear what to say: you run the test and keep track of which code is being visited. But what would you like to do with assert (in code)? If the assert statement is executed by some unit test, well, the code is obviously checked for a test. If this is not the case, should some code around the assert statement be considered a closed test? How much code would you like to consider included? All this becomes really unpleasant, and I do not believe that there is any right solution for this.

In addition, all indicators shown by labels are at least smelly - the very fact of the existence of a test that reaches some code does not say much about its correctness!

Can runners be confused by the fact that it was an application, not a statement of the specification that caused the error?

That was (IMO correct) William answered. Or is something missing? :)

+1
source

I usually recommend two approaches that seem to cover this:

  • Test in unit tests (I know this is not the same as the runtime statement, but you can verify that your reliability works in unit tests)

  • Compose your code so that the exit conditions are first and return . Then you have a flat (loose) space in which you can write your code after verification. If you like, you can write your own registrar / handler or "caller middleware" to abort for fatal errors.

0
source

All Articles