您现在的位置是:首页 >技术交流 >2305d很不错的模拟技术网站首页技术交流

2305d很不错的模拟技术

fqbqrr 2024-07-14 06:01:02
简介2305d很不错的模拟技术

D很不错.

这里有个.
今天,我正在编写一些迭代数据结构并把输出写进一堆不同文件的代码.它像这样:

void genSplitHtml(Data data, ...) {
    auto outputTemplate = File("template.html", "r");
    foreach (...) {
        auto filename = generateFilename(...);
        auto sink = File(filename, "w").lockingTextWriter;
        ...
        foreach (line; outputTemplate.byLine) {
            if (line.canFind("MAGIC_TOKEN")) {
                generateOutput(...);
            } else {
                sink.put(line);
            }
        }
    }
}

此函数的全部目的是把输出写入不同的(有自动确定名)文件,因此想编写一个单元测试来测试它是否创建了有正确内容的正确文件.
但是我也不想单元测试触及实际文件系统,不想在开发过程中清理混乱,因为代码有时会破坏并在临时目录中留下垃圾,或与其他并行运行的单元测试不好交互,等等.
而且不想重构来使genSplitHtml更可单元测试.这更可能搞砸并蔓延错误,这违背了本练习的目的.
所以我想出了如下方法:
1)重写函数为:

void genSplitHtml(File = std.stdio.File)(Data data, ...) { ... }

默认参数默认绑定到实际文件系统,因此用此函数的其他代码不必更改即可处理新的API.然后,对单元测试代码:
2)单元测试块中创建假的虚文件系统:

static struct MockFile {
    static string[string] files;
    string fname;
    this(string _fname, string mode) {
        //忽略此测试的"模式"
        fname = _fname;
    }
    //模拟替换`std.stdio.File.lockingTextWriter`
    auto lockingTextWriter() {
        return (const(char)[] data) {
            //模拟写入文件
            files[fname] ~= data.dup;
        };
    }
    void rewind() {} //挂名挂名
    void close() {} //
    auto byLine() {
        //主要写入文件,只读取指定的文件.所以在此只是`伪造`它的内容.
        if (fname != "template.html") return [];
        else return [
            "<html>",
            "MAGIC_TOKEN",
            "</html>"
        ];
    }
}

然后,单元测试不再调用genSplitHtml(...),而是调用genSplitHtml!MockFile(...),这用MockFile替换了std.stdio.File,

由于D的模板和区间API,其余代码会自动适应MockFile假文件系统.函数完成后,单元测试只需检查MockFile.files的内容,以验证是否存在正确的文件,及正确的内容.
花了大约10分钟来编写MockFile,及用假文件系统来检查正确行为的单元测试.
未来可扩展MockFile模拟,如完整的文件系统,偶尔(或总是)失败或破坏数据的文件系统等使用真实文件系统测试是不切实际的测试用例.

最重要的是,我"免费"获得所有这些:除了目标函数的单个新模板参数外,无需更改现有代码.

D不仅是r0x0rs,D是巨石!!

非常好!你展示的技术叫"模拟".在正确参数化函数输入和输出时,它特别有效.
我修复Dlexer.d为不再访问全局变量时,我可通过模拟输入和输出来简化它的单元测试.如,我不必使用全局"闭嘴"开关来抑制错误消息,而是使用闲着的模拟错误处理器.

是的,至少从Java时代开始,它就是个古老的技术.
但是,在该特例下,使它脱颖而出的是D可让你仅通过1行更改来模拟全局(模块级)符号引用.如,要模拟Java中的顶级"系统",你必须在外部包帮助下做一些神秘的侵改;

这很难.在D中,给函数添加单个模板参数,就可以了.*这就是*力量.
很高兴听到.错误阻塞是过去一些最令人恼火的D编译器错误的根源;越少使用它,就越好.

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。