zoukankan      html  css  js  c++  java
  • unittest.TestCase中测试用例执行顺序问题

     

     我们在做自动化测试用例的时候,通常会把一个个测试用例放到一个unittest.TestCase的扩展类中,当我们运行测试用例文件时,测试文件中的测试用例会随机执行的。如:

    #-*- coding: UTF-8 -*-

    import time

    import unittest

    import sys

     

    class DemoTest(unittest.TestCase):

     

        def setUp(self):

            ….

    Def test_a(self):

        ………

    Def test_b(self):

        ………

    Def test_c(self):

        ………

    Def test_d(self):

        ………

    Def tearDown(self):

        ………

    if __name__ == '__main__':

        suite = unittest.TestLoader().loadTestsFromTestCase(DemoTest)

        unittest.TextTestRunner(verbosity=2).run(suite)

    上面的示例是包含四个测试用例的一个测试用例集,在我们执行这个测试文件后,四个测试用例的执行顺序是随机的。如果这几个测试用例有依赖关系,则会影响你们用例的执行,于是我在想能不能控制一下测试用例的执行顺序呢?虽然测试用例相互之间不能有依赖关系,可是这算是一个尝试吧!我在网上查到一个方法,是适用于junit的:

                               换种顺序来执行TestCase(Junit适用)

    JunitTestCase,总是按固定的顺序执行的. 正如你在Eclipse中跑Run As Junit Test, 无论你跑多少次, TestCase的执行顺序都是一致的,可重复的. 这就导致一个问题, TestCase之间的独立性无法保证.

    例如下面一个Test类中的2TestCase:

    public class DaoTest {

     

        @Test

        public void test_count() {

            dao.insert(new User("root", "123456"));

            assertEquals(1, dao.count(User.class));

        }

     

        @Test

        public void test_insert() {

            dao.clear(User.class, null);

            dao.insert(new User("admin", "123456"));

            assertEquals(1, dao.count(User.class));

        }

     

    }

    如果先执行test_count()然后执行test_insert(),两个TestCase都能通过.

    但如果先执行test_insert(),然后执行test_count(),test_count()会失败.

    所以,有必要去打乱TestCase的默认执行顺序,以暴露出TestCase本身的问题. TestCase更可靠,才能让主代码更可靠.

    我实现了一个简单的方式,使用的是Junit的公开API, 测试过4.34.8.2,均可使用:

            //得到所有带@Test的方法,这里用的是Nutz的资源扫描,反正你能得到全部Test类就行

            List list = Scans.me().scanPackage("org.nutz");

            List reqs = new ArrayList();

            Map reqMap = new HashMap();

            for (Class clazz : list) {

                Method[] methods = clazz.getMethods();

                for (Method method : methods) {

                    if (method.getAnnotation(Test.class) != null) {

                        //将单个TestCase(即一个Test Method),封装为JunitTest Request

                        Request req = Request.method(clazz, method.getName());

                        reqs.add(req);

                        reqMap.put(req , method);//在最终打印测试结果时,方便查找具体出错的Method

                    }

                }

            }

     

            // 因为reqs 是一个List,我们可以按需调整TestCase的顺序

            // 正序 //nothing change.

            // 反序Collections.reverse(reqs)

            // 乱序Collections.shuffle(reqs)

     

            //把执行顺序保存下来,方便重现执行顺序

            try {

                FileWriter fw = new FileWriter("./test_order.txt");

                for (Request request : reqs) {

                    fw.write(reqMap.get(request).toString());

                    fw.write(" ");

                }

                fw.flush();

                fw.close();

            }

            catch (IOException e) {}

     

            //到这里, List已经按我们预期的方式排好,可以执行测试了

            final TestResult result = new TestResult();

            RunNotifier notifier = new RunNotifier();

            notifier.addListener(new RunListener() { //需要设置一个RunListener,以便收集测试结果

     

                public void testFailure(Failure failure) throws Exception {

                    result.addError(asTest(failure.getDescription()), failure.getException());

                }

                public void testFinished(Description description) throws Exception {

                    result.endTest(asTest(description));

                }

                public void testStarted(Description description) throws Exception {

                    result.startTest(asTest(description));

                }

     

                public junit.framework.Test asTest(Description description) {

                    return new junit.framework.Test() {

     

                        public void run(TestResult result) {

                            throw Lang.noImplement();

                        }

     

                        public int countTestCases() {

                            return 1;

                        }

                    };

                }

            });

            //来吧,执行之!!

            for (Request request : reqs) {

                request.getRunner().run(notifier);

            }

     

            //接下来,就是打印结果了.

            System.out.printf("Run %d , Fail %d , Error %d ", result.runCount(), result.failureCount(), result.errorCount());

     

            if (result.failureCount() > 0) { //断言失败的TestCase

                Enumeration enu = result.failures();

                while (enu.hasMoreElements()) {

                    TestFailure testFailure = (TestFailure) enu.nextElement();

                    System.out.println("--Fail------------------------------------------------");

                    System.out.println(testFailure.trace());

                    testFailure.thrownException().printStackTrace(System.out);

                }

            }

     

            if (result.errorCount() > 0) { //抛异常的TestCase

                Enumeration enu = result.errors();

                while (enu.hasMoreElements()) {

                    TestFailure testFailure = (TestFailure) enu.nextElement();

                    System.out.println("--ERROR------------------------------------------------");

                    System.out.println(testFailure.trace());

                    testFailure.thrownException().printStackTrace(System.out);

                }

            }

    , 考验一下你的TestCase!! 让它在乱序中多次执行. Nutz按这种思路,已经爆出几个Bug(当然,我已经迅速fix)

    https://github.com/nutzam/nutz/blob/master/test/org/nutz/AdvancedTestAll.java

    python中不好用,于是只好想一下其他的方法了。我想是不是可以把每个测试用例变成函数,然后再写一个函数来顺序调用它们呢?

    这个方法虽然可以控制顺序,可以也有一定的风险,如果出错了,不会按测试用例给报错,不能准确地统计出测试用例地正确率!如果全部通过则没有问题,可是影响报告的结果,需要想办法来美化一下报告。

    修改后的代码如下:

    #-*- coding: UTF-8 -*-

    import time

    import unittest

    import sys

     

    class DemoTest(unittest.TestCase):

     

        def setUp(self):

            ….

    Def a(self):

        ………

    Def b(self):

        ………

    Def c(self):

        ………

    Def d(self):

        ………

    Def  test_demo(self):

        a()

        b()

        c()

        d()

    Def tearDown(self):

        ………

    if __name__ == '__main__':

        suite = unittest.TestLoader().loadTestsFromTestCase(DemoTest)

        unittest.TextTestRunner(verbosity=2).run(suite)

     

    ----夫英雄者,胸怀大志,腹有良谋,有包藏宇宙之机,吞吐天地之志者也。
  • 相关阅读:
    linux下ssh端口的修改和登录
    linux找回密码
    XAMPP命令之LAMPP
    VirtualBox 复制vdi文件和修改vdi的uuid
    探讨PHP页面跳转几种实现技巧
    CSS盒模型和margin重叠
    8--数组旋转
    9--斐波那契数列
    7--动态规划
    6--树的遍历
  • 原文地址:https://www.cnblogs.com/eagleking0318/p/6520976.html
Copyright © 2011-2022 走看看