Mejores prácticas TDD: validación de objetos Java y código limpio

Suppose a Java class called Car, whose objects are initialized through a static factory:

public class Car {

    private String name;

    private Car(String name){//...}

    public static Car createCar(String name){
        //mechanism to validate the car attributes
        return new Car(name);
    }
}

Of course, I want to extract Validation process into a dedicated class named CarValidator.

There are two ways of providing this validator to the factory:

Not stubbable/mockable validator:

public static Car createCar(String name){
     new CarValidator(name); // throw exception for instance if invalid cases
     return new Car(name);
}

Stubbable/mockable validator:

public static Car createCar(CarValidator carValidator, String name){ //ideally being an interface instead
    carValidator.validate(); 
    return new Car(name);
}

It look likes a redundancy here: CarValidator ya contiene name value since it stores Car parameters as its own fields (a priori cleanest way), thus we could bypass the second argument like this:

public static Car createCar(CarValidator carValidator){ 
     carValidator.validate();  
     return new Car(carValidator.getName());
}

However, this looks unclear... why would a Car find its values from a Validator => no sense.

So, we could refactorate like this:

public static Car createCar(CarValidator carValidator, String name){ 
                        carValidator.validate(name); // throwing exception for instance if invalid cases
                        return new Car(carValidator.name());
}

Sounds pretty less weird, but CarValidator looses the benefit from creating fields rather than passing arguments to each of its necessary private methods like:

private checkForCarName(String name); 

¿Qué método debo elegir?

preguntado el 05 de mayo de 13 a las 21:05

1 Respuestas

My proposition is following: I would not mix validation of domain object with the object itself.

It would be a lot more cleaner if domain object would assume that the data passed to it are valid, and validation should be performed somewhere else (e.g. in a factory, but not necessary).

In that "factory" you would perform data preparation state (validation, vulnerability removal etc.) and then you would create a new object.

You will be able to test the factory (if it is validating properly) and not the domain object itself.

contestado el 05 de mayo de 13 a las 21:05

Sorry but I disagree. Validation object mechanism should be described out of the domain class, no doubt on that fact. But in order to ALWAYS keep an object in a cohesive state and especially prevent someone to create it without using the "external" factory beforehand, one must validate it BEFORE its creation and thus validation should be called through domain class. I think especially for immutable class. - Mik378

I believe a good approach here would be to use the Fluent Builder pattern. That way the class Car itself can be made immutable and the Car.Builder class would contain all necessary validation rules. - Olaf

@Olaf Yes, but that doesn't solve the problem. Consequence of your solution: violation of SRP. And if we want to solve SRP, even with a beautiful fluent builder we'd come back to my question in the post. - Mik378

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.