Unit testing 在一个干净的体系结构中测试做不止一件事的Interactor方法

Unit testing 在一个干净的体系结构中测试做不止一件事的Interactor方法,unit-testing,clean-architecture,Unit Testing,Clean Architecture,我一直在阅读有关单元测试的书籍&并试图实现涉及这两个方面的东西 据我所知,一个干净的体系结构是结构化的,以便可以对Interactor对象的方法进行单元测试 但是,当用例类似于“创建一个文件,其中的内容是以某种格式从某些数据中计算出来的”时,我会感到困惑,因为它不是单一的(有文件内容的计算和文件的创建,这两者都在用例中) 下面是一些说明我的情况的伪代码: /* We are in an Interactor (i.e. UseCaseObject) * This method 1)comput

我一直在阅读有关单元测试的书籍&并试图实现涉及这两个方面的东西

据我所知,一个干净的体系结构是结构化的,以便可以对Interactor对象的方法进行单元测试

但是,当用例类似于“创建一个文件,其中的内容是以某种格式从某些数据中计算出来的”时,我会感到困惑,因为它不是单一的(有文件内容的计算和文件的创建,这两者都在用例中)

下面是一些说明我的情况的伪代码:

/* We are in an Interactor (i.e. UseCaseObject)
 * This method 1)computes fileContent and 2)writes it into a file. 
 */
public void CreateFileFromData(someDataInSomeFormat) {
    var parsedData = SomeParser.Parse(someDataInSomeFormat);

    string fileContent = ???; 

    WriteFile(fileContent); 
}
我的问题如下:

  • Interactor中定义的方法必须是统一的吗?(例如,只做一件事)
  • Interactor中定义的方法必须经过单元测试吗?(我将函数(无论是否为单一函数)视为可测试单元,如果不正确,请更正)
  • 哪个类必须在干净的体系结构中保存文件内容的计算

  • 您不知道用于计算的数据将从何处“加载”,但例如,让我们假设数据将从另一个文件读取

    您的交互者将有三个依赖项
    -读取文件
    -计算新文件的数据
    -写入文件

    public class Interactor
    {
        public Interactor(IReader reader, ICalculator calculator, IWriter writer)
        { }
    
        public void DoJob()
        {
            var data = reader.Read();
            var calculatedData = calculator.Calculate(data);
            writer.Write(calculatedData);
        }
    }
    
    通过这种方法,
    交互者将负责“组合”完成任务所需的步骤

    您可以通过模拟所有依赖项来简单地测试Interactor

    其中:
    IReader
    IWriter
    是网关
    ICalculator
    interactior使用的用例的实现细节

    Interactor中定义的方法必须是统一的吗?(例如,只做 (一件事)

    方法应该做一件事——执行与用例相关的任务。如果任务需要使用网关(外部资源),或者任务很复杂,无法将其保存在一个方法中,那么您将引入所有必需的单元作为依赖项,交互者的责任是将它们“粘合”在一起

    Interactor中定义的方法必须经过单元测试吗?(我看到一个 函数,无论是否为单一的,作为可测试单元,如果 这是不正确的)

    只抽象网关(外部资源)-然后您可以测试interactor的整个逻辑。如果您先编写测试-您将编写测试,整个逻辑可以在一个函数中(它可能/应该是丑陋的spagetti代码,这会使测试通过)。然后,当您看到整个实现过程时,您可以开始通过将内容移动到专用类来移动员工

    哪个类必须以干净的方式保存fileContent的计算 建筑


    如果是简单的单行计算,它可以是交互器。但我更喜欢为计算引入专用类,并将其作为依赖项引入。虽然测试将保留在interactor中,专用计算类将通过interactor测试进行测试,但Clean体系结构的一个核心方面是所有应用程序业务逻辑都在interactor方法中。这意味着你也希望你的主要测试集中在交互者身上,通常使用单元测试和低级验收测试

    在设计你的交互方法时,你仍然应该遵循SRP:应该只有一个改变的理由。 你也可以结合互动者来遵循SRP

    如果文件内容的计算是u的应用程序业务逻辑,那么它应该在Interactor方法中


    有关互动者的详细讨论,请查看我的帖子:

    谢谢你的回答。然而,它没有提到干净的体系结构,我的问题是它所固有的。您提到“数据将‘加载’到哪里”这一事实似乎表明您的答案超出了Clean体系结构的范围,因为后者通过确定的概念(如“实体”和“网关”)来处理这类事情。您能更清楚地说明您的答案如何适合干净的体系结构吗?谢谢!最后一件事:即使你回答了我的第三个问题,你能否在你的回答中澄清全部三个问题的答案,以供未来读者参考?根据我的理解,应该是:[1:No][2:Yes][3:interactior实现接口的实现细节]再次感谢!再想一想,在阅读之后,似乎一个好的单元测试是一个在我改变函数内部时不会中断的测试。据我所知,您的方法将创建一个测试,在我决定更改Interactor函数的内部时,该测试将中断!(参见我的链接中提供的非常类似的示例)@Minh-T–mTRAN-check更新的答案。你只需要抽象(模拟)依赖关系,这会使测试变慢(外部资源)。我在这篇文章中读到的东西帮助我,教会了我很多东西(这导致我花了2天时间阅读各种各样的书籍),事后我发现了问题的答案。当我输入自己的答案时,我意识到它都包含在你的答案中。很抱歉,我的想法花了这么长时间才成熟到可以像现在这样阅读你的答案。我将您的答案标记为答案:)出于建设性的目的,这绝对不是对您答案的反馈,而是对我的问题的反馈,现在我找到了问题的答案(非常感谢您在这里和您的文章中的所有链接),我意识到事实上我只将WriteFile()视为用例的主要和最后一步,这让我重新考虑把计算放在哪里;事实上,情况恰恰相反,写文件代码必须从交互程序移开。显然,你猜不到所有这些,我只是想说,以防它能帮助你在其他帖子中发现真正的问题:)