如何有效地创建和使用构建器模式

Wou*_*ort 5 c# unit-testing design-patterns builder-pattern

在我们的最后一个项目中,我们最终得到了一个用于单元测试的共享测试夹具,这给出了很多问题.所以在我们当前的项目中,我已经研究了构建器模式.我们在开发机器上的内存中运行我们的单元测试,并在构建服务器上运行数据库.

目前我有一个T4模板,例如为学生生成以下构建器:

public class StudentBuilder : Builder<Student, StudentBuilder>
{
    public StudentBuilder()
    {
        IsMale = true;
    }

    public StudentBuilder WithFirstName(string firstName)
    {
        this.FirstName = firstName;
        return this;
    }

    public StudentBuilder WithLastName(string lastName)
    {
        this.LastName = lastName;
        return this;
    }

    public StudentBuilder WithIsMale(bool isMale)
    {
        this.IsMale = isMale;
        return this;
    }

    internal override Student Construct()
    {
        Student result = new Student()
        {
            FirstName = FirstName ?? "FirstName:" + id.ToString(),
            LastName = LastName ?? "LastName:" + id.ToString(),
            IsMale = IsMale,
            Id = id,
        };

     /   return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过基类我可以通过以下方式使用它:

Student wouter = StudentBuilder.Build()
    .WithFirstName("Wouter")
    .WithLastName("de Kort");
List<Student> students = StudentBuilder.Build().Multiple(10, (builder, index) => builder.WithFirstName("FirstName" + index));
Run Code Online (Sandbox Code Playgroud)

我们在构建服务器上运行集成测试,以确保一切都适用于数据库.这意味着我们必须确保满足所有参考约束.但问题就此开始了.

例如,学生需要有导师,导师属于学校,学校属于城市,城市属于....

这将导致代码如下:

StudentBuilder.Build().WithMentor(MentorBuilder.Build().WithSchool(SchoolBuilder.Build().WithCity(CityBuilder.Build()))
Run Code Online (Sandbox Code Playgroud)

我应该如何优化这个?我想过在每个Builder的Construct方法中做'默认构建',但如果我要建立10个学生,那么它将导致10个城市10个学校中的10个导师....

或者也许创建像WithAllCity(..),WithAll(School)这样的方法

有任何想法吗?我实际上是以正确的方式使用Builder Pattern吗?导演课可以帮忙吗?或者我应该从StudentBuilder继承哪些类来解决这些不同的情况?

或者另一个想法,我应该在将数据发送到数据库之前在我的服务层中添加更多验证吗?然后我会在内存数据库的单元测试中捕获更多错误.

Joe*_*ley 1

如果你的单元测试将使用学生的导师、导师的学校和学校的城市,我认为单元测试有代码来构建所有这些是合理的,但我建议你的单元测试可能不会测试就一件事。让您的单元测试更加具体,这样它们就不会深入研究如此多的属性。

如果问题不是你的单元测试,而是你的学生类要求将一个导师输入到其构造函数中,并且该导师不能为空,请考虑放宽该要求以允许空导师(我想是我的偏好),或者使构建器按照您所说填写“默认”对象。如果您尝试访问默认对象的属性,您甚至可以使默认对象抛出异常,提示您单元测试需要您构建“实际”对象。