简体   繁体   English

如何用N个不同的路径测试功能?

[英]How to test a function with N distinct paths?

I have a function which validates a model class where it has to check every member of the class to be non-null or non-empty in case of a String. 我有一个验证模型类的函数,在该模型类中,它必须检查类的每个成员(如果为String)为非空或非空。

The logic for this is_complete function is something like this: 这个is_complete函数的逻辑是这样的:

def is_complete(profile):
    if profile.first_name in (None, ''):
        return False
    elif profile.last_name in (None, ''):
        return False
    elif profile.dob is None:
        return False
    .
    .
    .# and checks so on for all members of the profile instance
    .
    .

    return True

My question since the number of possible paths the execution can take is quite large and increases in proportion to the number of member variables of profile to be checked, how does one reliably write tests for all the possible paths? 我的问题是,由于执行可能采用的可能路径数量很大,并且与要检查的profile的成员变量数量成比例地增加,因此如何可靠地为所有可能的路径编写测试?

Right now, I have two simple test cases: 现在,我有两个简单的测试用例:

  1. where only some of the members are set and checks assertFalse(is_complete(foo)) 仅设置一些成员并检查assertFalse(is_complete(foo))
  2. where all the members are set and checks assertTrue(is_complete(foo)) 设置所有成员并检查assertTrue(is_complete(foo))

But I have a feeling that this may not be enough. 但是我感觉这可能还不够。

I'm not sure what you mean by having MxN paths. 我不确定使用MxN路径意味着什么。 In the posted code you have as many paths as fields + 1. 在发布的代码中,路径的数量与字段+ 1相同。

Create a helper method that creates a profile that is complete and passes is_complete . 创建一个辅助方法,该方法创建一个完整的profile并传递is_complete

Add a test method to verify is_complete(profile) is True for the complete profile . 添加一个测试方法来验证is_complete(profile)是否为True完整profile

Add one test method for each field, with the following steps: 为每个字段添加一种测试方法,包括以下步骤:

  • Call the helper method to create a complete profile that we know would pass is_complete 调用helper方法以创建一个完整的配置文件,我们知道该配置文件将通过is_complete
  • Break the field under test 打破被测领域
  • Verify that is_complete returns False 验证is_complete返回False

You will have as many test methods as fields + 1. 您将拥有与字段+ 1一样多的测试方法。

Btw, instead of this: 顺便说一句,代替这个:

 if profile.first_name in (None, ''): 

You can writer simpler: 您可以写得更简单:

if not profile.first_name:

You can test this with randomization: 您可以使用随机测试:

  • Write a function that creates a random Profile object with all the fields filled (could be random, but valid). 编写一个函数,该函数创建一个随机的Profile对象,并填充所有字段(可以是随机的,但有效)。
  • Randomly change one or more fields to either None or empty 将一个或多个字段随机更改为无或为空
  • Pass the object to the is_complete() function. 将对象传递给is_complete()函数。

I can show this only in Java with Qala Datagen . 我只能使用Qala Datagen在Java中显示这一点 I assume you're interested in the negative paths, so it can look like this: 我假设您对否定路径感兴趣,因此它看起来像这样:

@Test void profileIsNotComplete_ifAtLeastOneFieldIsBlank() {
    Profile p = Profile.random();
    callOneOrMore(
        () -> profile.setName(nullOrEmpty()),
        () -> profile.setLastName(nullOrEmpty()),
        ...);
    assertFalse(profile.isComplete();
}

Note, that this code actually tests more - it also checks the combination of fields set to null/empty. 请注意,该代码实际上会测试更多-它还会检查设置为null / empty的字段的组合。 If in Python there are no such libs, you can write some utility methods for yourself. 如果在Python中没有此类库,则可以自己编写一些实用程序方法。

NB : only one path is going to be tested per one execution. 注意 :每执行一次将仅测试一条路径。 You can run it many times (a thousand?) to make sure that all the paths pass. 您可以运行多次(一千次?)以确保所有路径都通过。 Then in CI you can run it only once if this is not a mission-critical functionality and you're not afraid that it's going to break often. 然后,在CI中,如果这不是关键任务功能,并且您不担心它会经常中断,则只能运行一次。

Otherwise if you really want this to be covered 100% for every invocation , you can violate some of the good practices and just combine all these tests in one (otherwise there are going to be too many tests which complicate reading them): 否则,如果您真的希望每次调用都覆盖100%的代码 ,则可以违反一些良好做法,并将所有这些测试组合为一个(否则,太多的测试会使阅读它们变得复杂):

@Test void profileIsNotComplete_ifOneFieldIsBlank() {
    assertFalse(Profile.random().setName(null).isComplete());
    assertFalse(Profile.random().setName("").isComplete());

    assertFalse(Profile.random().setLastName(null).isComplete());
    assertFalse(Profile.random().setLastName("").isComplete());
    ...
}

This doesn't test combinations though, but you can combine both approaches. 虽然这不会测试组合,但是您可以组合两种方法。 The positive case is very easy in both approaches: 在这两种方法中,肯定的情况都很容易:

@Test void profileIsComplete_ifAllFieldsAreFilled() {
    assertTrue(Profile.random());
}

More info on randomized testing is here . 更多关于随机测试的信息在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM