shupsta2010 发表于 2021-11-12 10:40:13

让我们开始一个更深入的讨论,教人们(像我一样)如何应用TDD

我不是唯一一个看到或张贴论坛帖子寻求自动测试插件帮助的人。无论是单元测试还是集成测试,当开发AutoCAD的. NET插件时,期望的结果仍然是应用TDD的愿望。作为一个发表过这些帖子的人,我觉得它来自一个软件开发新手的地方,他不知道从哪里开始使用TDD。然后发现依赖AutoCAD运行测试有一层额外的困难。
现在,我已经阅读了Scott MacFarlane的《AutoCAD自动化测试》。NET API
https://forums . Autodesk . com/Autodesk/attachments/Autodesk/152/51134/1/讲义_ 2654 _ CP 2654 _ Automated _ testing . docx
虽然它很有帮助,但它也非常过时,依赖于Gallio,它似乎已经有一段时间没有更新了。
我还开始在自己的项目中使用CAD block的CADTest项目来测试
https://github . com/CAD block/CAD test
这是一个很棒的工具,尽管我在使用它时遇到过几次困难。但它只是一个工具,在一个没有经验的开发者手中只能做这么多。
我通常用例子来思考,所以我将使用一个我认为可能是很好的演示的个人例子。值得庆幸的是,这个工具已经开发出来了,但我现在在维护它:
假设我们想要一个工具来排列线条,以表示平面图上的托梁。该工具要求输入一条闭合多段线,然后输入托梁间距和托梁的方向(即EW或NS)。我可以看到手动运行一个测试,在那里我准备好了一条闭合折线,我输入我知道我要测试的间距和我要测试的方向,然后可以直观地检查它是否工作。但是如何通过自动化来实现呢?
我可以记录闭合折线的句柄,然后运行一个测试,将它输入到工具中,并对其他信息进行同样的操作。但是,如果不进行目视检查,我如何验证它的工作情况呢?
我认为这只是许多人试图克服困难的一个例子。我看到很多帖子,人们问如何对他们的插件进行单元测试,他们要么说这不太可行,要么只是简单地链接我已经提供的上面的一个链接。
我想我只是希望创建一个地方,让人们在谷歌“AutoCAD单元测试”时有希望得到一些答案。
感谢任何帮助,并阅读我的咆哮!
**** Hidden Message *****

JohnK 发表于 2021-11-12 12:57:25

函数返回类型与测试有很大关系,所以你的单元测试本质上就是测试1 = 1。
在该文档的开始设置中,作者提到了他们所谓的“代码隔离”,这是正确的,但比他们演示的要复杂一些。
第7页的代码开始讨论构建“隔离代码”的任务,但作者并没有完全理解这个概念(在我看来,这是一个非常糟糕的例子,但我们现在就用它吧)。
这是文档中的例程。
private void SetCircleColor(Circle circle) {
        if (circle.Radius10.0) {
                circle.ColorIndex = 1;
        } else {
                circle.ColorIndex = 3;
        }
}
要进行测试,您需要在构建例程时记住返回类型,因为尝试对一堆空白进行单元测试实际上是不可能的/有用的,所以您应该像这样构建“孤立的”例程:
public int drawcircle()...
public int getcircle()...
public int setcirclecolor()...
一个更好的例子是可以用几行代码编写的简单内容。
public int square(int a){
      return a*a;
}
public int add(int a, int b){
      return a+b;
}

您的测试应该是这样的:
assert.isequal(square(2), 4);
assert.isequal(add(1, 2) 3);
...
如您所见,这使得事情很容易跟踪。
我用C语言测试的代码非常简单(过分),但是完成了任务。
https://jera . com/tech info/jtns/jtn 002
这是一个更强大的版本,演示了自动化的过程。这实质上只是“返回类型”检查的扩展。如果您查看下面的示例文件“minunit_example.c ”,您应该能够看到MAIN将返回一个int。如果你查看“CI”文件夹,你会看到一个bat文件只是运行“minunit_example”并检查是否返回了一个传递的int。
https://github . com/siu/min unit
显然,随着您的运营变得更加复杂,您的回报也会变得更加复杂。也就是说,你开始为好的返回1,为坏的或其他类型的错误代码返回0,但是原则是成立的;在很大程度上,你需要对照预期结果来检查你的函数返回。
有些测试总是需要一些人工交互。例如,我正在构建一个“广度优先目录横向”的东西,我真的不能为此构建一个测试,所以我只是用一些样本文件构建了一个样本目录,并运行一个“测试程序”来查看目录是否以正确的顺序打印出来。它既不是自动化的,也不是精心制作的(只是一个把东西打印到命令行的程序),但是我真的不能为此建立一个验证。

shupsta2010 发表于 2021-11-12 13:57:15


感谢您的回复,这是非常有用的信息。我没有过多地考虑返回类型,因为我认为如果某个东西有效,它就会有效,如果无效,它就会抛出一个错误。但我现在明白这可能过于简单了。我在工作,所以我不能完全考虑你的回复的含义,但我想到的第一件事是尝试与我的原始帖子联系起来,让放置“托梁”线的函数返回它绘制的线的数量。这可以根据给定的已知折线进行测试。
或者更好的方法是在测试期间传入一个新的rectangle对象,因为已知矩形的尺寸,所以将放置已知数量的“托梁”。

JohnK 发表于 2021-11-12 14:26:48

我们正在讨论基础知识;对象测试有点复杂(MSDN有这方面的文档和教程)。但对于这一部分,您需要更好地了解回报。是的,你开始重新思考如何更好地开发你的例程是正确的(这是目标;重新思考你的程序的结构),创建一些行是一个伟大的步骤。或者,您可能还想尝试在成功时返回 1,在失败时返回 0。
Visual Studio,Microsoft,C#,Java等确实使整个测试过程复杂化,这并不一定是坏事,只是不同。在C#或Visual Studio中需要做的很多事情都会导致语言或工具努力简化编码体验(有点像“割掉鼻子以面对自己的脸”之类的事情)。-即,使用MSTest Unit测试方法的使用方式与我上面描述的不同,因为您将方法添加到代码中,而不是像上面示例那样构建实际的测试文件。
但是,所有这些最终将导致您在函数设计中使用“断言”,“尝试”等路径。我一直坚持更传统的路线 - 即我现在每天用C / C++编程,我在文本编辑器中键入源代码,然后将这些文件发送到编译器。因此,当我处理一个函数或一系列函数时,我大部分时间都花在开发代码头(名称,描述,返回)上,然后是实际代码。这最终成为代码的规范。这种方法使我成为异端,大多数人做MSTest单元测试方法并将方法添加到他们的代码中(这对我来说似乎更像是事后的想法),但我至少可以引导你进入这个兔子洞主题的正确洞。

JohnK 发表于 2021-11-12 14:53:51

链接发布时间...
传统单元测试的基础知识本质上是函数返回,从而验证函数是否返回正确的数字,但在较新的代码设计中,这很快就会变得混乱!旧方法产生了这样的代码结构:
if (!drawcircle()) {
      // oops! get out now!
      return;
}
,但现在我们有一个新方法(微软做它最擅长的事情;改变东西)叫做“AAA方法模式的东西”,看起来更像:
try{
      drawcircle()
} catch (system.overheat) {
      assert.contains("some thing");
}

这是一个指向MSDN教程的链接。
https://docs.microsoft.com/en-us/visualstudio/test/walkthrough-creating-and-running-unit-tests-for-managed-code?view=vs-2022

shupsta2010 发表于 2021-11-12 15:19:31

因此,如果我在下面,您所描述的是两种不同的单元测试方法。人们或多或少地想知道在设计方法签名时他们打算使用哪种方法。不过,这两种方法都假设您正在为测试创建一个单独的文件/类。这个类可以说是实例化该类或使用被测方法的内容,并且可以记录旧方法的返回(比如零),或者记录在某种类型的尝试捕获中捕获的异常。
我在使用CADTest时有一些使用断言的经验,通过在测试中实例化一个类,并向构造函数提供某些输入,然后使用断言测试实例化对象的状态。

JohnK 发表于 2021-11-12 15:48:34

如果您只使用基于AutoCAD的实用程序,您将使用MSTest单元测试方法,但一般来说,只编写“private void”类型的例程可以看出您有多马虎(在我看来)。如果您正在编写一个很好的银行注册例程(如MS教程),我认为您可以通过使用更传统的测试方法来获得
例如,给定以下函数:
public void Withdraw(double amount) {
    if(m_balance >= amount) {
      m_balance -= amount;
    } else {
      throw new ArgumentException(nameof(amount), "Withdrawal exceeds balance!");
    }
}
在我看来,以下测试是在浪费每个人的时间。花时间设计一个有地板和天花板的好功能,比如“撤回”功能,你不需要测试

public void Withdraw_AmountMoreThanBalance_Throws()
{
    // arrange
    var account = new CheckingAccount("John Doe", 10.0);
    // act and assert
    Assert.ThrowsException(() => account.Withdraw(20.0));
}
如果我编写了“提取”函数,我会让它返回经常账户余额(一个盲函数调用/返回除了抛出异常之外没有其他好处),并在主调用函数中处理-也就是说,我不会让异常一开始就发生。不同的学派。

shupsta2010 发表于 2021-11-12 16:32:42

这是一个很好的细分和例子。在考虑测试时,我也有这种感觉。在 AutoDesk 大学的讲义中,当您编写已知会失败的测试时,他们会解释 TDD,然后编写代码以使其通过,并且在编写测试之前不要编写任何代码。那么在这种情况下,你怎么能开始编写一个类来容纳你想要的函数作为我的托梁示例。然后,如果你确实写了一个因为该类不存在而失败的测试,那么你让它通过现有的类,这又有什么用呢?
所以我喜欢你编写一个返回有用东西的函数的思维方式,它是调用函数的责任来处理它返回的内容。我们如何将其应用于AutoCAD测试?
页: [1]
查看完整版本: 让我们开始一个更深入的讨论,教人们(像我一样)如何应用TDD