0

好吧,我对测试很陌生,但我想将编程提升到一个新的水平并开始测试,没有单元测试,而是高级测试。例如:插入一个作业并通过检查它的输入和结果来检查它是否有效。或者另一个例子:插入一个工作并且工人 X 启动它:现在我将检查工作和工人的属性,以了解它们是否处于有效状态。

但这非常复杂,所以我一直在考虑在每个测试中做一个环境和一个实例,每个环境创建一个服务器实例并分配一个空数据库来使用;

例如 start job 高级案例:

var environment = new GenericEnvironment(test); // test will be used to throw errors within the environment when something goes wrong.
environment.insertWorker({name: 'bla bla', number 99});
environment.insertARandomProduct();
environment.insertJob({productId: product._id})
environment.startJob({workerId: worker._id})
var environmentValidator = new environmentValidators.StartJobEV()
var job = environment.getLastInsertedJob(environment, test);
environment.validate(job);
// node.js (Javascript on server)

这个例子非常简单,因为在现实世界中它使用异步回调。

environmentValidator 使用来自环境的数据来检查作业是否处于有效状态。例如,还要让正在工作的工作人员检查它的状态是否很忙。

但我不认为这很好,因为我正处于创建测试的开始阶段,所以我问你是否有可能改进进行这些高级测试的方式。

另外我想知道这些测试是否有任何现有的框架?

谢谢

真实世界的代码,但仅用于在插入作业后检查状态:

    var serverManager = new ServerManager(test.getPathForDatabase());
    require('production/tests/tottys/_environments/DefaultEnvironment');
    var environment = new production.tests.tottys._environments.DefaultEnvironment(test, serverManager);

    var dummyData = {}

    test.addStep('initEnvironment', function(nextStep){
        environment.init();
        environment.addListener('afterInitialized', function(){
            nextStep();
        }, this);
    });

    test.addStep('insertWorker', function(nextStep){
        dummyData.worker = environment.insertRandomWorker(function(data){
            nextStep();
        });
    });

    test.addStep('insertProduct', function(nextStep){
        dummyData.product = environment.insertRandomProduct(function(data){
            nextStep();
        });
    });

    test.addStep('insertJob', function(nextStep){
        var worker = environment.getLastInsertedWorker();
        var product = environment.getLastInsertedProduct();
        dummyData.job = environment.insertRandomJob(worker, product, function(data){
            nextStep();
        });
    });

    test.addStep('updateWorker', function(nextStep){
        environment.updateWorker({workerId: environment.getLastInsertedWorker()._id}, function(data){
            nextStep();
        });
    });

    test.addStep('validateInsertedJob', function(nextStep, test){
        require('production/tests/tottys/_environmentValidators/AfterJobInserted');
        var EV = new production.tests.tottys._environmentValidators.AfterJobInserted(environment, test);
        var job = environment.getLastInsertedJob();
        EV.addListener('validationEnded', function(e){
            nextStep();
        });
        EV.validate(job, dummyData);
    });
    test.start();

和验证文件:

qx.Class.define("production.tests.tottys._environmentValidators.AfterJobInserted", {
     extend: qx.core.Object


    ,properties: {
    }


    ,events: {
        validationEnded: 'qx.event.type.Data'
    }


    ,construct: function(environment, test){
        this.__environment = environment;
        this.__test = test;
    }


    ,members: {
        validate: function(job, dummyData){
            this.__job = job;
            this.__dummyData = dummyData;
            this.__environment.getWorkerForJob(job, this.__afterWorkerReturned, this);
            this.__environment.getProductForJob(job, this.__afterProductReturned, this);
        }



        ,__afterWorkerReturned: function(worker){
            this.__worker = worker;
            this.__tryStartValidation();
        }



        ,__afterProductReturned: function(product){
            this.__product = product;
            this.__tryStartValidation();
        }



        ,__tryStartValidation: function(){
            if(this.__preConditionsAreValid()){
                this.__startValidation();
            }
        }



        ,__preConditionsAreValid: function(){
            if(this.__worker && this.__product){
               return true;
            }
            return false;
        }



        ,__startValidation: function(){
            var test = this.__test;
            var dummyData = this.__dummyData;
            var job = this.__job;
            var worker = this.__worker;
            var product = this.__product;

            test.add("Expect job not to be done.", function(expect){
                expect(job.done).toBe(false);
            })

            test.add("Expect job's requested quantity to be the same as requested.", function(expect){
                expect(job.qtdRequested).toBe(dummyData.job.qtdRequested);
            })

            test.add("Expect job's missing quantity be the same as requested.", function(expect){
                expect(job.qtdMissing).toBe(dummyData.job.qtdRequested);
            })

            test.add("Expect to be requested by the same request type.", function(expect){
                expect(job.requestedByType).toBe('manager')
            })

            test.add("Expect job not to be done.", function(expect){
                expect(job.done).toBe(false);
            })

            test.add("Expect job's done quantity to be '0' (Number)", function(expect){
                expect(job.qtdDone).toBe(0);
            })

            test.add("Expect job to not have any time frames.", function(expect){
                expect(job.timeFrames && job.timeFrames.length > 0).notToBe(true);
            })

            test.add("Expect job's date end to not exist.", function(expect){
                expect(job.dateJobEnd).notToExist();
            })

            test.add("Expect job's date request to exist.", function(expect){
                expect(job.dateRequested).toExist();
            })

            test.add("Expect job's state to be 'todo'.", function(expect){
                expect(job.state).toBe('todo');
            })

            test.add("Expect job's order to be '0' (Number).", function(expect){
                expect(job.order).toBe(0);
            })

            test.add("Expect job's worker's name to be the same as the requested one.", function(expect){
                expect(job.forWorker.name).toBe(dummyData.worker.name);
            })

            test.add("Expect job's worker's number to be the same as the requested one.", function(expect){
                expect(job.forWorker.number).toBe(dummyData.worker.number);
            })

            test.add("Expect job's worker's _id to be the same as the generated one.", function(expect){
                console.log(worker);
                expect(job.forWorker._id.toString()).toBe(worker._id.toString());
            })

            test.add("Expect job's product's code to be the same as the requested one.", function(expect){
                expect(job.product.code).toBe(dummyData.product.code);
            })

            test.add("Expect job's product's description to be the same as the requested one.", function(expect){
                expect(job.product.description).toBe(dummyData.product.description);
            })

            test.add("Expect job's product's _id to be the same as the requested one.", function(expect){
                expect(job.product._id.toString()).toBe(product._id.toString());
            })
            this.fireDataEvent('validationEnded', {err: false})
        }
    }

});
4

1 回答 1

1

如果您从测试开始,那么做“高级”或“集成测试”(IT)总是很诱人。它比“单纯”的单元测试感觉更自然、更“简单”、更强大。你已经让整个系统运行起来了,为什么不以此为基础进行测试呢?

但与软件开发一样,IT 意味着您有更多的依赖关系。如果要运行这些测试,数据库必须处于某种状态。服务器将不得不运行。您将需要一个浏览器。网络应该可以工作。对于 IT 而言,整个系统必须处于精确定义的状态,并且您需要工具来使系统处于这种状态 - 您必须在每次单独测试之前这样做。

问题:每个依赖项都是错误的来源。如果依赖项的数量达到某个点,其中一个将始终被破坏,并且您的测试将失败。不是因为代码被破坏了,而是因为创建初始状态太复杂了。

这就是为什么你应该真正从单元测试开始。找到系统中没有依赖关系的最小组件并对其进行测试。

这种方法的优点:

  1. 它降低了复杂性。与 IT 相比,测试通常或总是会成功。
  2. 测试用例会更小。你不会花一个小时来弄清楚你需要什么初始状态以及最终状态应该是什么。
  3. 设置会更简单(通常,你不会有任何或 1-2 行设置)
  4. 依赖项的更改不会破坏其他测试。有了 IT,一个微小的变化就可以打破所有其他测试。
  5. 如果您知道所有单独的组件都可以正常工作,那么其余代码中的错误将自动消失。
  6. 修复错误会容易得多。如果您只测试 10 行代码,那么这 10 行代码中必然存在任何错误。如果您运行 IT,则错误可能在任何地方。

结论:获取jasmine并从一些单元测试开始。当您对所有内容进行单元测试时,为整个系统编写 IT 将变得更加简单……如果您需要的话。

于 2012-09-07T11:51:42.820 回答