使用相同的工具对Excel公式和VB进行单元测试?

时间:2016-05-11 21:48:31

标签: excel vba excel-vba unit-testing

是否有任何工具允许在Excel中单独测试Excel公式和Visual Basic表单?我找到的方法可以做一个或另一个,但不是两个。例如,Rubberduck看起来很有希望测试VBA,但似乎不允许在Excel电子表格中测试公式。

2 个答案:

答案 0 :(得分:0)

我在Excel中找到“单元测试”功能的唯一方法是在工作簿中创建一个工作表,其目的是作为验证页面。在此工作表中定义各种附加功能,以查找工作簿中的边缘情况和检查添加等。

保留一个注释字段以及一个布尔成功字段是非常有用的,该字段可以聚合以在您的其他输入页面上放置自定义格式消息,以便将用户提示给失败的“单元测试”。

这种方法可以很好地使您的测试可重用,并且对工作簿的最终用户也是透明的。

答案 1 :(得分:0)

可以使用FlyingKoala对Excel公式和VBA进行单元测试。 FlyingKoala是xlwings的扩展。

xlwings提供了一个COM包装器,该包装器能够从Python执行VBA(通过让Excel运行它)。这是一个很棒的库/解决方案。来自ZoomerAnalyitics的受人尊敬的Felix已经撰写了blogpost,涉及使用带有示例的xlwings进行VBA单元测试。

FlyingKoala使用库(xlcalculator)将Excel公式转换为Python,然后可以在Python的unittest框架中对其进行单元测试。因此,可以评估公式并对照已知目标值(无论该值是Excel还是预先定义的)进行检查。

在Excel运行时使用FlyingKoala进行单元测试的公式示例;

import unittest
import logging

import xlwings as xw
from flyingkoala import FlyingKoala
from pandas import DataFrame
from pandas import Series
from numpy import array
from numpy.testing import assert_array_equal
from pandas.testing import assert_series_equal

logging.basicConfig(level=logging.ERROR)

class Test_equation_1(unittest.TestCase):

    def setUp(self):

        self.workbook_name = r'growing_degrees_day.xlsm'

        if len(xw.apps) == 0:
            raise "We need an Excel workbook open for this unit test."

        self.my_fk = FlyingKoala(self.workbook_name, load_koala=True)
        self.my_fk.reload_koala('')
        self.equation_name = xw.Range('Equation_1')

        if self.equation_name not in self.my_fk.koala_models.keys():
            model = None
            wb = xw.books[self.workbook_name]
            wb.activate()
            for name in wb.names:
                self.my_fk.load_model(self.equation_name)
                if self.equation_name == name.name:
                    model = xw.Range(self.equation_name)
                    self.my_fk.generate_model_graph(model)

            if model is None:
                return 'Model "%s" has not been loaded into cache, if named range exists check spelling.' % self.equation_name


    def test_Equation_1(self):
        """First type of test for Equation_1"""

        xw.books[self.workbook_name].sheets['Growing Degree Day'].activate()

        goal = xw.books[self.workbook_name].sheets['Growing Degree Day'].range(xw.Range('D2'), xw.Range('D6')).options(array).value

        tmin = xw.books[self.workbook_name].sheets['Growing Degree Day'].range(xw.Range('B2'), xw.Range('B6')).options(array).value
        tmax = xw.books[self.workbook_name].sheets['Growing Degree Day'].range(xw.Range('C2'), xw.Range('C6')).options(array).value
        inputs_for_DegreeDay = DataFrame({'T_min': tmin, 'T_max': tmax})
        result = self.my_fk.evaluate_koala_model('Equation_1', inputs_for_DegreeDay).to_numpy()

        assert_array_equal(goal, result)


    def test_Equation_1_predefined_goal(self):
        """First type of test for Equation_1"""

        goal = Series([0.0, 0.0, 0.0, 0.0, 0.0, 5, 10, 15, 20])

        tmin = [-20, -15, -10, -5, 0, 5, 10, 15, 20]
        tmax = [0, 5, 10, 15, 20, 25, 30, 35, 40]
        inputs_for_DegreeDay = DataFrame({'T_min': tmin, 'T_max': tmax})
        result = self.my_fk.evaluate_koala_model('Equation_1', inputs_for_DegreeDay)

        assert_series_equal(goal, result)


    def test_VBA_Equation_1(self):
        """
        The function definition being called;

        Function VBA_Equation_1(T_min As Double, T_max As Double) As Double
            VBA_Equation_1 = Application.WorksheetFunction.Max(((T_max + T_min) / 2) - 10, 0)
        End Function
        """

        goal = 20

        vba_equation_1 = xw.books[self.workbook_name].macro('VBA_Equation_1')
        result = vba_equation_1(20.0, 40.0)

        self.assertEqual(goal, result)