2

I am coming around with TDD/BDD.

I am a bit confused though, when it comes to initially writing my BDD tests and then adding more tests after the very broad tests.

For Example, lets say that I am giving requirements first:

  • It should take in an array.
  • It should print a list.
  • It should look for this specific condition.

I then write my tests:

describe('myApp', function (){
    it('should take in an array',function(){
        //expect
    });
    it('should print a list',function(){
        //expect
    });
    it('should look for this specific condition',function(){
        //expect
    });
});

Now I need to add some functionality to my app to pass these tests, so say I write a function that checks to see if the app is actually passed an array. Or do I just check the input in the app itself? Example:

myApp(anArray) {
    checkArray(anArray) // returns true or false
}

So now my app has a new method.. checkArray(). So I need to refactor my tests, but how do I modify them. Questions:

  • Do I write a new describe block?
  • Can/should i put a describe block inside an it block?
  • Should that be in my should be an array test?

    describe('myApp', function (){
     it('should take in an array',function(){
        describe('myApp.checkArray, {
            it('should return true given an array', function(){
                //assertORexpectORwhatever
            });
        });
    });
    

    });

OR should add the describe block after the first describe block like I always see, but then my initial SHOULD is no longer describing myApp. For example:

describe('myApp', function (){
    describe('myApp.checkArray, {

        //Describes myApp, not the checkArray function... *my problem*
        it('should take in an array',function(){ 

            it('should return true given an array', function(){
                //assertORexpectORwhatever
            })
        })
    });
});

Am I doing something fundamentally wrong? Am i describing my problem well enough?

1 Answer 1

1

The way you compose tests will tend to differ based on your own techniques and those of your team, but there are a couple of basics that would help in your situation:

In the first case where you're asking about the test it('should take in an array',...: I think the problem you're running into isn't a shortcoming of TDD/BDD, it's that this test is going to be difficult to positively prove in JavaScript (type checking with a flexible type system is hard). You're probably only going to be able to prove that your function rejects items that are not arrays or have array properties, which is likely to be good enough at any rate.

When you are looking to satisfy a test, you shouldn't typically add functions solely for the purpose of responding to your test suite; though in some cases it may actually be useful to add a function such as checkArray -- especially if you intend to throw an error if the check fails. Either way, your objects will need some way to communicate with the test suite - so add whatever functionality you need in order for it to do so; sometimes this is as simple as returning the correct results from your method calls.

There aren't any hard/fast rules for what should be inside of which kind of block -- when I'm using a test framework with describe/it grammar I use describe blocks to group functionality I think is part of a related set of behaviors and might nest them under something like a describe block for my Entire App. My inner describe blocks might be scoped to all of the things in a specific module or file, it could be related to a particular step of the application's life-cycle (initialization, operation, termination, etc.), or it could even be just a single object/function within my program.

I'm not any kind of authority on testing or what exactly your files should look like (I mentioned it depends on you and your team earlier, right?), but here is what one of my jasmine test suites looks like and it works for me:

describe("myApp.ViewModel", function() {
    beforeEach(function() {
        //setup some stuff relevent to every test
        //maybe instantiate the object to test
        //setup spies and other mock objects - spying on getJSON maybe...
    })
    describe("the constructor", function() {
        it("should return a specific type of object", function() {});
        it("should be defined but internally uninitialized", function() {});
        it("should have specific methods defined on its prototype", function() {
            // maybe I would even do sub `it` calls here, but not really required
        });
    });
    describe("initAsync", function() {
        it("should initialize the ViewModel asynchronously", function() {});
        it("should throw an error when initialized with no endpoint", function() {});
        it("should load 3 records initialized with the `data.svc/mock1` endpoint", function() {});
        it("should load 0 records initialized with the `data.svc/mock2` endpoint", function() {});
        // ...
    });
    describe("submitAsync", function() {
        // ...
    });
});
describe("myApp.Utils", function() {
    // ...
});

You can imagine the entire code set above grouped inside of a describe("myApp", ...) block, if that made things easier to work with.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.