Python 如何对验证日期时间是否为特定ISO格式的函数进行单元测试?

Python 如何对验证日期时间是否为特定ISO格式的函数进行单元测试?,python,unit-testing,datetime,Python,Unit Testing,Datetime,我对单元测试还不熟悉,我想要一些关于这个主题的指导。该函数首先验证datetime是否为字符串,如果是,则验证其是否为正确的ISO格式 if not isinstance(timestamp,str): raise ValueError("timestamp must be a string") try: datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S') return True except ValueError:

我对单元测试还不熟悉,我想要一些关于这个主题的指导。该函数首先验证datetime是否为字符串,如果是,则验证其是否为正确的ISO格式

if not isinstance(timestamp,str):
    raise ValueError("timestamp must be a string")
try:
    datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S')
    return True
except ValueError:
    return True

如何确定单元测试中要包含哪些内容以及应该注意哪些内容?

关键是要提出边缘案例。这在很大程度上取决于问题领域的经验,你在过去看到过哪些处理datetimes的bug。但幸运的是,当您在等待Lyft或其他程序时发现并修复bug或想到奇怪的情况时,您总是可以添加更多的单元测试

datetimes有一些特别的事情需要注意,但请注意,其中很多事情,在测试是否正在做决定之前,您首先必须决定要做什么

当然,请确保非字符串会引发ValueError。包括字节。 个位数的天数和月份2018-3-06是否为有效日期? 同样,对于小时、分钟和秒,但有时您想要的规则是不同的。 不同的分隔符-例如2018-03-06 12:13:14是有效的ISO时间戳,但根据您的规则无效。就这一点而言,20180306T12:13:14以及许多其他变体也是如此。 所有明显的过去结束值,如第0个月或第13个月,但奇数例外情况见下文,如第二个60。 时间戳在过去太远,代码的其他部分无法处理。例如,ISO允许日期在1960年,但如果您的代码要将日期传递给处理uint32 Unix时间戳的API,就您而言,这些日期无效。 第0000年。根据ISO8601,这意味着公元前1年,但您可能不希望这样。 两位数的年份。一位数、三位数和五位数年份。和负年份,以及带有显式+前缀的年份。ISO 8601建议使用四位数年份,如0030,但也建议允许使用+和-前缀,这是处理公元前1年之前年份的唯一方法,并且通常通过信息交换合作伙伴的同意,允许使用10010等年份。 分数秒。有人会超过你2018-06-20T15:16:17.890。 时区/偏移指示器。有人会超过你2018-06-20T15:16:17Z。 2月29日闰年(包括2000年)和非闰年(包括1900年)。 闰秒-例如,2005-12-31T23:59:60 UTC或2006-01-01T08:59:60日本当地时间。 由于DST转换而不存在的小时数,如果您与当地时间打交道,例如2018-03-11T02:30:00在美国大部分地区不存在。 如果你与当地时间打交道,关心过去,比如1752年英国缺少的11天,1918年俄罗斯缺少的13天,那么由于日历转换而不存在的日子。
关键是提出边缘案例。这在很大程度上取决于问题领域的经验,你在过去看到过哪些处理datetimes的bug。但幸运的是,当您在等待Lyft或其他程序时发现并修复bug或想到奇怪的情况时,您总是可以添加更多的单元测试

datetimes有一些特别的事情需要注意,但请注意,其中很多事情,在测试是否正在做决定之前,您首先必须决定要做什么

当然,请确保非字符串会引发ValueError。包括字节。 个位数的天数和月份2018-3-06是否为有效日期? 同样,对于小时、分钟和秒,但有时您想要的规则是不同的。 不同的分隔符-例如2018-03-06 12:13:14是有效的ISO时间戳,但根据您的规则无效。就这一点而言,20180306T12:13:14以及许多其他变体也是如此。 所有明显的过去结束值,如第0个月或第13个月,但奇数例外情况见下文,如第二个60。 时间戳在过去太远,代码的其他部分无法处理。例如,ISO允许日期在1960年,但如果您的代码要将日期传递给处理uint32 Unix时间戳的API,就您而言,这些日期无效。 第0000年。根据ISO8601,这意味着公元前1年,但您可能不希望这样。 两位数的年份。一位数、三位数和五位数年份。和负年份,以及带有显式+前缀的年份。ISO 8601建议使用四位数年份,如0030,但也建议允许使用+和-前缀,这是处理公元前1年之前年份的唯一方法,并且通常通过信息交换合作伙伴的同意,允许使用10010等年份。 分数秒。有人会超过你2018-06-20T15:16:17.890。 时区/偏移指示器。有人会超过你2018-06-20T15:16:17Z。 2月29日闰年(包括2000年)和非闰年(包括1900年)。 闰秒-例如,2005-12-31T23:59:60 UTC或2006-01-01T08:59:60日本当地时间。 由于DST转换而不存在的小时数,如果您与当地时间打交道,例如2018-03-11T02:30:00在美国大部分地区不存在。 由于日历转换而不存在的天数,如果您处理的是当地时间,并且关心过去,例如,日历中缺少的11天 1752年的英国,1918年的俄罗斯13天,等等。
首先,我看不到该函数返回False的任何方法。首先,我看不到该函数返回False的任何方法。当然,对于大多数测试,它实际上是在测试具有自己测试的基础datetime库。也许其中有一个子集足以检查此函数中实际实现的代码?@jsbueno如果您希望的行为是“Python datetime库所做的一切都是正确的”,这通常适用于快速脏脚本,或用于在各种应用程序中与stdlib密切合作的严肃库,你不需要做太多的测试。但是如果你的目标是“处理这个输入”,那么你需要测试一切。如果某个程序失败是因为程序库有一个bug,或者是因为它不是为实现您想要的功能而设计的,但您没有意识到这一点,或者其他原因,那么它仍然是一个失败,您仍然需要决定如何处理它。所以你应该对它进行单元测试。@jsbueno尽管如此,你的大部分代码从一开始就不是一个简单的stdlib函数包装器……当它是的时候,仔细检查stdlib单元测试并确保他们正在测试的行为实际上是你想要的行为可能是个好主意,当然,对于大多数这些测试,它实际上是在测试具有自己测试的基础datetime库。也许其中有一个子集足以检查此函数中实际实现的代码?@jsbueno如果您希望的行为是“Python datetime库所做的一切都是正确的”,这通常适用于快速脏脚本,或用于在各种应用程序中与stdlib密切合作的严肃库,你不需要做太多的测试。但是如果你的目标是“处理这个输入”,那么你需要测试一切。如果某个程序失败是因为程序库有一个bug,或者是因为它不是为实现您想要的功能而设计的,但您没有意识到这一点,或者其他原因,那么它仍然是一个失败,您仍然需要决定如何处理它。所以你应该对它进行单元测试。@jsbueno尽管如此,你的大部分代码从一开始就不是一个简单的stdlib函数包装器……当它是的时候,仔细检查stdlib单元测试并确保他们正在测试的行为实际上是你想要的行为可能是个好主意,即使你不打算只是复制或使用它们。