In my domain layer have the class:
public class Telefone : IEntity
{
public virtual int Id { get; protected internal set; }
public virtual string Tipo { get; set; }
public virtual string Numero { get; set; }
}
The Id is protected internal. This is deliberate, who generates the Id is the database and should be ReadOnly.
But in the test layer, must have access to the setter of this property.
So in my domain layer added the attribute in AssemblyInfo.cs:
[assembly: InternalsVisibleTo("MyTestLayer")]
This will allow me to set the Id in tests layer but not in the domain layer!
In test layer
new Telefone().Id = 1; // Works!!
In UI layer
new Telefone().Id = 1; // Not compile! Not works!
var pessoa = fix.Build<Pessoa>()
.With(p => p.Nome)
.Do((pess) =>
{
fix.Build<Telefone>()
.With(p => p.Id)
.With(p => p.Tipo)
.With(p => p.Numero)
.OmitAutoProperties()
.CreateMany(10).ToList().ForEach(pess.Telefones.Add);
fix.Build<Email>()
.With(p => p.Id)
.With(p => p.Tipo)
.With(p => p.Endereco)
.OmitAutoProperties()
.CreateMany(10).ToList().ForEach(pess.Emails.Add);
})
.OmitAutoProperties()
.Create();
Theoretically, the above code should work, but when my road test an error occurs:
The property "Id" is read-only.
All properties Id
s are protected internal
.
In the same file, same test can do something like:
new Telefone().Id = 1; // Works!!
new Email().Id = 1; // Works!!
This clearly tells you that you have a _leaky abstraction_ in your Domain Model. A Domain Model should not be designed with any particular boundary technology in mind.
This particular issue is very clearly telling you that your Domain Model is _not_ reusable.
InternalsVisibleTo
has no effect because it only allows access to your test library, but AutoFixture is a different assembly entirely. This just tells you that _no_ other client will ever be able to reuse your Domain Model.
The best course of action is to reconsider your API design. Normally, I'd do something like this:
``` c#
public class Telefone : IEntity
{
public Telefone(int id)
{
this.Id = id;
}
public virtual int Id { get; private set; }
public virtual string Tipo { get; set; }
public virtual string Numero { get; set; }
}
```
This generated a lot of discussion in a group of architecture that I follow.
There is a major problem with this approach:
max (id) + 1
and then set the Id of my object. But how to set the Id if it is readonly?Agreed that these are all _problems_. All four of them _strongly_ indicate that the Domain Model depends on the persistence layer, and can't be made to work without it.
I understand the problem. I can not change the PKs type to Guid, would really work.
I understand now that the problem is not related to AutoFixture, but if you're interested. I create a sample project to discuss this.
thanks.