I'm struggling to learn how to make tests, to test specifically and only business logic/rules in the Service layer only, using Moq tests.
Here's part of my project:
The Entity:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
}
The Repository:
public class ClientRepository : IClientRepository
{
private MyContext context;
public ClientRepository(MyContext context)
{
this.context = context;
}
public void Save(Client client)
{
try
{
context.Clients.Add(client);
context.SaveChanges();
}
catch (Exception)
{
throw new Exception("Error saving");
}
}
public void Delete(Client client)
{
Client cl = context.Clients.Where(x => x.Id == client.Id).FirstOrDefault();
if (cl != null)
{
context.Clients.Remove(client);
context.SaveChanges();
}
else
{
throw new Exception("Error deleting");
}
}
public List<Client> List()
{
return context.Clients.ToList();
}
public Client GetById(int Id)
{
return context.Clients.Where(x => x.Id == Id).FirstOrDefault();
}
}
The Repository Interface:
public interface IClientRepository
{
void Save(Client client);
void Delete(Client client);
List<Client> List();
Client GetById(int Id);
}
The Service:
public class ClientService
{
private ClientRepository rep;
public ClientService(MyContext ctx)
{
this.rep = new ClientRepository(ctx);
}
public void Save(Client client)
{
try
{
Validate(client);
rep.Save(client);
}
catch (Exception ex) {
Debug.WriteLine(ex.Message);
throw new Exception("Error Saving");
}
}
public void Delete(Client client)
{
try
{
if (client.Name.StartsWith("A"))
{
throw new Exception("Can't delete client with name
starting with A");
}
rep.Delete(client);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw new Exception("Error deleting");
}
}
public List<Client> List()
{
try
{
return rep.List();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw new Exception("Error list");
}
}
public void Validate(Client client)
{
if (client.Name.Length < 2)
{
throw new Exception("nome deve ser maior que 2");
}
}
public Client GetById(int Id)
{
return rep.GetById(Id);
}
}
My test:
[TestMethod]
public void CantSaveClientWithNameLengthLessThanTwo()
{
Client client = new Client() { Id = 4, Name = "a" };
var mockMyContext = new Mock<MyContext>();
mockMyContext.Setup(c => c.Clients.Add(client)).Throws<InvalidOperationException>();
var service = new ClientService(mockMyContext.Object);
service.Save(client);
int listCount = service.List().Count();
Assert.AreEqual(0, listCount);
}
In this test I want to test the business logic which prevents me from saving a client with a name that has less than 2 characters. Of course, this test is working incorrectly, and I end up getting an exception.
I'd like to know how to implement a test to test these 2 business requirements, and only that, in my project:
- Can't save a client with less than 2 characters in the name.
- Can't delete a client whose name starts with "A".
I'm using Microsoft Visual Studio 2010, Entity Framework 4.0 and Moq.
I appreciate any kind of help I can get, and suggestions of changes that I should make in the project, only if it isn't possible to accomplish what I want with my actual project pattern.