I have a simple Http module:
public class CustomLoggingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public void BeginRequest(object sender, EventArgs eventArgs)
{
//some code
}
public void EndRequest(object sender, EventArgs eventArgs)
{
//some
}
public void Dispose()
{
}
}
How can I unit test this? Especially how is it possible to mock events? Can anyone give some simple example?
Not sure why you have decided to hardwire the dependencies as new LogService() and new HttpContextWrapper(HttpContext.Current) within the CustomLoggingModule. If want to test whether LogInfo() method is called or not, it becomes lot easier if you can externalize these dependencies so you can inject stubbed/mocked version etc.
Also your question does not state that you are using an IOC container. You can register the HttpModule with the container and provide external dependencies at runtime. Your question also does not state that using an isoloation/mock object framework.
Therefore I will provide you with a solution that you can verify whether LogInfo method is called, using hand written stubs and mocks.
To achieve this, we need to refactor CustomLoggingModule a bit, so it becomes more testable.
System Under Test (SUT)
public class CustomLoggingModule : IHttpModule
{
public ILogService LogService { get; set; }
public Func<ILoggingHttpContextWrapper> LogginHttpContextWrapperDelegate { get; set; }
public void Init(HttpApplication context) {
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public CustomLoggingModule() {
LogginHttpContextWrapperDelegate = () => new LoggingHttpContextWrapper();
}
public void BeginRequest(object sender, EventArgs eventArgs) {
LogService.LogInfo(LogginHttpContextWrapperDelegate().HttpContextWrapper);
}
public void EndRequest(object sender, EventArgs eventArgs) {
//some
}
public void Dispose(){ }
}
As you see above, I have introduced 2 additional properties - ILogService so I can provide a Mocked verion and a delegate Func which allows me to stub the
new HttpContextWrapper(HttpContext.Current);
public interface ILoggingHttpContextWrapper {
HttpContextWrapper HttpContextWrapper { get; }
}
public class LoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public LoggingHttpContextWrapper() {
HttpContextWrapper = new HttpContextWrapper(HttpContext.Current);
}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
And then your real ILogService
public interface ILogService {
void LogInfo(HttpContextWrapper httpContextWrapper);
}
public class LogService : ILogService {
public void LogInfo(HttpContextWrapper httpContextWrapper)
{
//real logger implementation
}
}
Unit Test :
You would create a MockLoggerService, so you can verify the interaction i,e whether the LogInfo() method was called, etc. You also need a stubbed LoggingHttpContextWrapper to provide the fake HttpContextWrapper to the SUT (System Under Test)/ CustomLoggingModule.
public class StubLoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public StubLoggingHttpContextWrapper(){}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
public class MockLoggerService : ILogService
{
public bool LogInfoMethodIsCalled = false;
public void LogInfo(HttpContextWrapper httpContextWrapper) {
LogInfoMethodIsCalled = true;
}
}
MockLoggerService is very important. It is not the real logger service, but it is the mocked version. When we do public class MockLoggerService : ILogService this means that we are providing another layer of indirection to the logger service so we can verify the interaction of the behaviour.
You also notice that I have provided a boolean variable to verify whether the LogInfo method is called or not. This allows me to call this method from the SUT, and verify whether the method being called or not.
Now Your Unit Test can be implemented as below.
[TestMethod]
public void CustomLoggingModule_BeginRequest_VerifyLogInfoMethodIsCalled()
{
var sut = new CustomLoggingModule();
var loggerServiceMock = new MockLoggerService();
var loggingHttpContextWrapperStub = new StubLoggingHttpContextWrapper();
sut.LogService = loggerServiceMock;
sut.LogginHttpContextWrapperDelegate = () => loggingHttpContextWrapperStub;
sut.BeginRequest(new object(), new EventArgs());
Assert.IsTrue(loggerServiceMock.LogInfoMethodIsCalled);
}
I had the same issue with my custom http module and decided I won't give up that easily and will do all I can to trigger the BeginRequest event in unit test. I had to actually read through the source code of HttpApplication class and use reflection to invoke the method.
[TestMethod]
public void EventTriggered_DoesNotError()
{
using (var application = new HttpApplication())
{
var module = new CustomLoggingModule();
module.Init(application);
FireHttpApplicationEvent(application, "EventBeginRequest", this, EventArgs.Empty);
}
}
private static void FireHttpApplicationEvent(object onMe, string invokeMe, params object[] args)
{
var objectType = onMe.GetType();
object eventIndex = (object)objectType.GetField(invokeMe, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandlerList events = (EventHandlerList)objectType.GetField("_events", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandler handler = (EventHandler)events[eventIndex];
Delegate[] delegates = handler.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, args);
}
}
Related
I am new to TDD. Also new to MVP and Rxjava. I just dive into it and It is worth it. But I stuck at the testing part. I understand the basis of unit testing. It is a little bit difficult for me in beginning. But I stuck here and So how can test the presenter?
Here is the Presenter class -
public class NewsPresenter {
private final RxjavaService service;
private final MainView view;
private CompositeSubscription subscriptions;
public NewsPresenter(RxjavaService service, MainView view) {
this.service = service;
this.view = view;
subscriptions = new CompositeSubscription();
}
public void getNewsList(String urlQ){
view.showWait();
Subscription subscription = service.getNews(urlQ ,new RxjavaService.GetNewsCallback() {
#Override
public void onSuccess(Articles articles) {
view.removeWait();
view.getNewsListSuccess(articles);
}
#Override
public void onError(NetworkError networkError) {
view.removeWait();
view.onFailure(networkError.getAppErrorMessage());
Log.i("huh",networkError.getMessage());
}
});
subscriptions.add(subscription);
}
public void onStop(){
subscriptions.unsubscribe();
}
}
Here is the View Interface -
public interface MainView {
void showWait();
void removeWait();
void onFailure(String appErrorMessage);
void getNewsListSuccess(Articles articles);
}
Here is the RxJavaService class -
public class RxjavaService {
private final NewsRestService newsRestService;
public RxjavaService(NewsRestService newsRestService) {
this.newsRestService = newsRestService;
}
public interface GetNewsCallback {
void onSuccess(Articles articles);
void onError(NetworkError networkError);
}
public Subscription getNews(String q, final GetNewsCallback getNewsCallback) {
Log.i("stuck","service called");
return newsRestService.getNewsBySearch(q,"8dca7dea475e41e49518b2c61131e118",100)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(new Func1<Throwable, Observable<? extends Articles>>() {
#Override
public Observable<? extends Articles> call(Throwable throwable) {
return Observable.error(throwable);
}
})
.subscribe(new Subscriber<Articles>() {
#Override
public void onCompleted() {
Log.i("stuck","complete");
}
#Override
public void onError(Throwable e) {
getNewsCallback.onError(new NetworkError(e));
Log.i("stuck",e.getMessage());
}
#Override
public void onNext(Articles articles) {
getNewsCallback.onSuccess(articles);
Log.i("stuck","Onnext");
}
});
}
}
Here is the Test class where I am stuck-
#RunWith(MockitoJUnitRunner.class)
public class NewsListTest {
private NewsPresenter newsPresenter;
#Mock
private RxjavaService rxjavaService;
#Mock
private MainView mainView;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
newsPresenter = new NewsPresenter(rxjavaService,mainView);
}
#After
public void tearDown() throws Exception {
mainView = null;
newsPresenter.onStop();
}
#Test
public void Testing_The_Result() {
}
}
First things first
If you're into TDD, you'd never get into the situation you described. In TDD you start with a failing test, and just then go write the implementation. So your question is much more about testing then TDD.
I would recommend switching to RxJava2, as RxJava1 reaches End Of Life on March 31.
Look strange to me that RxJavaService changes the API from publish/subscribe to callbacks. Why not stick with rx API all the way to presenter?
Test with mocked RxJavaService
If you'd like to finish writing the test with the setup you have in the test, it would look something like this:
#Test
public void Testing_The_Result() {
final RxjavaService.GetNewsCallback[] callback = new RxjavaService.GetNewsCallback[1];
Mockito.when(rxjavaService.getNews(ArgumentMatchers.anyString(), ArgumentMatchers.any(RxjavaService.GetNewsCallback.class))).thenAnswer(new Answer<Subscription>() {
public Subscription answer(InvocationOnMock invocationOnMock) {
callback[0] = invocationOnMock.getArgument(1);
return mock(Subscription.class);
}
});
newsPresenter.getNewsList("some url");
Articles articles = new Articles();
callback[0].onSuccess(articles);
verify(mainView).removeWait();
verify(mainView).getNewsListSuccess(articles);
}
You can get rid of the ugly code by not using Mockito to mock RxJavaService, but rather roll you own hand-written mock, which would store the callback and provide it to the test.
However, I'd recommend a different approach.
Test with real RxJavaService and mocked NewsRestService
I'd say it makes more sense and gives a better test if we mocked only the NewsRestService:
#RunWith(MockitoJUnitRunner.class)
public class NewsList2Test {
private NewsPresenter newsPresenter;
#Mock
private MainView mainView;
#Mock
private NewsRestService newsRestService;
#Before
public void setUp() {
newsPresenter = new NewsPresenter(new RxjavaService(newsRestService), mainView);
}
#Test
public void show_success_in_view_when_there_are_articles() {
when(newsRestService.getNewsBySearch(eq("some url"), anyString(), anyInt()))
.thenReturn(Observable.just(new Articles()));
newsPresenter.getNewsList("some url");
verify(mainView).removeWait();
verify(mainView).getNewsListSuccess(any(Articles.class));
}
}
Having some issues getting my repository to retrieve information - keeps coming back null. Any Thoughts would be appreciated - new to this and teaching myself.
Repository:
public class CustomerRepository : ICustomerRepository
{
private masterContext context;
public CustomerRepository(masterContext context)
{
this.context = context;
}
public IEnumerable<Customer> GetCustomers()
{
return context.Customer.ToList();
}
public Customer GetCustomerById(int customerId)
{
var result = (from c in context.Customer where c.CustomerId == customerId select c).FirstOrDefault();
return result;
}
public void Save()
{
context.SaveChanges();
}
Controller:
public class CustomerController : Controller
{
private readonly ICustomerRepository _repository = null;
public ActionResult Index()
{
var model = (List<Customer>)_repository.GetCustomers();
return View(model);
}
public ActionResult New()
{
return View();
}
}
MasterContext which i had efc make:
public partial class masterContext : DbContext
{
public masterContext(DbContextOptions<masterContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.CustomerName).IsRequired();
});
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Order> Order { get; set; }
}
I think you need to create instances of you Context and your Repository. So in your Controller you need to something like this:
private masterContext context = new masterContext();
private ICustomerRepository repository = new CustomerRepository(context);
I assume that you're not using Dependency injection ... if so you just need to create a Constructor for your Controller that takes CustomerRepository as argument:
public CustomerController(ICustomerRepository _repository) {
repository = _repository;
}
If you did not configure your database context, look here: https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html
This will than enable you the dependency injection. Everything you than need to do for the Repository is to use
services.AddScoped<ICustomerRepository,
CustomerRepository>();
And I think it could be good to remove the ToList() in the Repository class and remove the Cast List<Customer> in your Controller and use ToList() instead, if it's really needed. Because if you're using it in the View the ienumerable could also work.
I have implemented UnitOfWork and GenericRepository following some tutorials.
I have IEFDbContext/EFDbContext class that takes care about Database, my IUnitofWork is as follows...
public interface IUnitOfWork : IDisposable
{
IGenericRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
And IGenericRepository as follows
public interface IGenericRepository<T> where T : class
{
IQueryable<T> Get();
T GetByID(object id);
void Add(T entity);
void Delete(T entity);
void DeleteAll(IEnumerable<T> entity);
void Update(T entity);
bool Any();
}
My controller is as follows...
public class ProjectController : Controller
{
private IGenericRepository<Project> ProjectRepo { get; set; }
private IUnitOfWork _unitOfWork { get; set; }
public ProjectController(IUnitOfWork uow)
{
_unitOfWork = uow;
ProjectRepo = _unitOfWork.GetRepository<Project>();
}
}
My create action is as follows
[HttpPost]
public ActionResult Create(AddProjectModel model)
{
if (ModelState.IsValid)
{
ProjectRepo.Add(newProject);
_unitOfWork.Save();
}
}
Everything works when I run the application, I am aware about why to use IuitofWork and GenericRepository, and that is why I am not creating IProjectRepository and then injecting that here...
My question is with unit testing this action.
I have created MockGenericRepository and MockUnitofWork in my Test project as follows...
public class MockUnitOfWork<TContext> : IUnitOfWork where TContext : class, new()
{
private TContext _ctx;
private Dictionary<Type, object> _repositories;
public MockUnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
}
public IGenericRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
if (_repositories.Keys.Contains(typeof(TEntity)))
{
return _repositories[typeof(TEntity)] as IGenericRepository<TEntity>;
}
var entityName = typeof(TEntity).Name;
var prop = _ctx.GetType().GetProperty(entityName);
MockRepository<TEntity> repository = null;
if (prop != null)
{
var entityValue = prop.GetValue(_ctx, null);
repository = new MockRepository<TEntity>(entityValue as List<TEntity>);
}
else
{
repository = new MockRepository<TEntity>(new List<TEntity>());
}
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void SetRepositoryData<TEntity>(List<TEntity> data) where TEntity : class
{
IGenericRepository<TEntity> repo = GetRepository<TEntity>();
var mockRepo = repo as MockRepository<TEntity>;
if (mockRepo != null)
{
mockRepo._context = data;
}
}
public void Save()
{
}
public void Dispose()
{
}
}
And MockGenericRepository as follows
public class MockRepository<T> : IGenericRepository<T> where T : class
{
public List<T> _context;
public MockRepository(List<T> ctx)
{
_context = ctx;
}
public IQueryable<T> Get()
{
return _context.AsQueryable();
}
public T GetByID(object id)
{
// return _context.Find(s => s.Id == id).SingleOrDefault();
throw new NotImplementedException();
}
public virtual void Add(T entity)
{
_context.Add(entity);
}
public virtual void Delete(T entity)
{
_context.Remove(entity);
}
public virtual void DeleteAll(IEnumerable<T> entity)
{
_context.RemoveAll(s => s == entity);
}
public virtual void Update(T entity)
{
var entry = _context.Where(s => s == entity).SingleOrDefault();
entry = entity;
}
public virtual bool Any()
{
return _context.Any();
}
}
My ProjectControllerTest is as follows...
public class ProjectControllerTest
{
private readonly List<ALCProject> _projectsList;
private readonly IUnitOfWork _mockU = new MockUnitOfWork<EFDbContext>();
private ProjectController GetControllerObject()
{
foreach (var project in _projectsList)
{
_mockU.GetRepository<Project>().Add(project);
}
var controller = new ProjectController(_mockU);
return controller;
}
[Fact]
public void TestCreateProject()
{
var controller = GetControllerObject();
var result = controller.Create(new AddProjectModel());
Assert.Equal(_mockU.GetRepository<Project>().Get().Count(),4);
}
The issue I have is that my test does passes but when I look inside _mockU.GetRepository().Get() I can see that a new project is added but the "ID" field is 0, I understand the reason for this is because my MockGenericRepsoiotry has context define as public List _context; and that why its just adding new project in the list.
Can someone guide me how can I make it to generate new ID I think I have to Fake EFDbContext but I dont know how ???
The Project has an Id of 0 because nothing is setting it to anything else! It is most likely the Id property of the entity is mapped to an identity column in your database (SQL Server as a guess). When DbContext.Save() is called, it performs an insert operation in SQL. SQL Server is generating a new unique Id value for that row, returning this back to Entity Framework. EF then populates the value back into the object that it was persisting.
Your mock unit of work doesn't actually call DbContext.Save(), despite the fact that it is using the EF context as the data store for the repositories that it returns. You could enhance it by putting code in your MockUnitOfWork<T>.Save() method to provide a number to any Id property that has a value of zero in any of the repositories.
Or, as you say, this is a unit test so perhaps you shouldn't care.
I cannot quite see why your unit of work mock is looking at the Entity Framework context at all. Why not always return a repository based on a List<TEntity>?
I have been given the task to evaluate codeFirst and possible to use for all our future projects.
The evaluation is based on using codeFirst with an existing database.
Wondering if it's possible to mock the repository using codeFirst 4.1.(no fakes)
The idea is to inject a repository into a service and moq the repository.
I have been looking on the net but I have only found an example using fakes.I dont want to use fakes I want to use moq.
I think my problem is in the architecture of the DAL.(I would like to use unitOfWork etc.. by I need to show a working moq example)
Below is my attempt(Failed miserably) due to lack of knowledge on Code first 4.1.
I have also uploaded a solution just in case somebody is in good mood and would like to change it.
http://cid-9db5ae91a2948485.office.live.com/browse.aspx/Public%20Folder?uc=1
I am open to suggestions and total modification to my Dal.Ideally using Unity etc.. but I will worry about later.
Most importantly I need to be able to mock it. Without ability to use MOQ we will bin the project using EF 4.1
Failed attempt
//CodeFirst.Tests Project
[TestClass]
public class StudentTests
{
[TestMethod]
public void Should_be_able_to_verify_that_get_all_has_been_called()
{
//todo redo test once i can make a simple one work
//Arrange
var repository = new Mock<IStudentRepository>();
var expectedStudents = new List<Student>();
repository.Setup(x => x.GetAll()).Returns(expectedStudents);
//act
var studentService = new StudentService(repository.Object);
studentService.GetAll();
//assert
repository.Verify(x => x.GetAll(), Times.AtLeastOnce());
}
}
//CodeFirst.Common Project
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public interface IStudentService
{
IEnumerable<Student> GetAll();
}
//CodeFirst.Service Project
public class StudentService:IStudentService
{
private IStudentRepository _studentRepository;
public StudentService()
{
}
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public IEnumerable<Student> GetAll()
{
//TODO when mocking using moq this will actually call the db as we need a separate class.
using (var ctx = new SchoolContext("SchoolDB"))
{
_studentRepository = new StudentRepository(ctx);
var students = _studentRepository.GetAll().ToList();
return students;
}
}
}
//CodeFirst.Dal Project
public interface IRepository<T> where T : class
{
T GetOne(Expression<Func<T, bool>> predicate);
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
T Single(Func<T, bool> predicate);
T First(Func<T, bool> predicate);
}
public class RepositoryBase<T> : IRepository<T> where T : class
{
private readonly IDbSet<T> _dbSet;
public RepositoryBase(DbContext dbContext)
{
_dbSet = dbContext.Set<T>();
if (_dbSet == null) throw new InvalidOperationException("Cannot create dbSet ");
}
protected virtual IDbSet<T> Query
{
get { return _dbSet; }
}
public T GetOne(Expression<Func<T, bool>> predicate)
{
return Query.Where(predicate).FirstOrDefault();
}
public IEnumerable<T> GetAll()
{
return Query.ToArray();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return Query.Where(predicate).ToArray();
}
public void Add(T entity)
{
_dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public T Single(Func<T, bool> predicate)
{
return Query.Where(predicate).SingleOrDefault();
}
public T First(Func<T, bool> predicate)
{
return Query.Where(predicate).FirstOrDefault();
}
}
public class SchoolContext:DbContext
{
public SchoolContext(string connectionString):base(connectionString)
{
Database.SetInitializer<SchoolContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Not sure why I have to do this.Without this when using integration testing
//as opposed to UnitTests it does not work.
modelBuilder.Entity<Student>().ToTable("Student"); }
public DbSet<Student> Students { get; set; }
}
public interface IStudentRepository:IRepository<Student>
{
}
public class StudentRepository : RepositoryBase<Student>, IStudentRepository
{
public StudentRepository(DbContext dbContext)
: base(dbContext)
{
}
public IEnumerable<Student> GetStudents()
{
return GetAll();
}
}
Again feel free to modify or whatever is needed to help me to get something together.
Thanks a lot for your help
When I started with repository and unit of work patterns I used the implementation similar to this (it is for ObjectContext API but converting it to DbContext API is simple). We used that implementation with MOQ and Unity without any problems. By the time implementations of repository and unit of work have evolve as well as the approach of injecting. Later on we found that whole this approach has serious pitfalls but that was alredy discussed in other questions I referenced here (I highly recommend you to go through these links).
It is very surprising that you are evaluating the EFv4.1 with high emphasis on mocking and unit testing and in the same time you defined service method which is not unit-testable (with mocking) at all. The main problem of you service method is that you are not passing repository/context as dependency and because of that you can't mock it. The only way to test your service and don't use the real repository is using some very advanced approach = replacing mocking and MOQ with detouring (for example Moles framework).
First what you must do is replacing your service code with:
public class StudentService : IStudentService
{
private readonly IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public IEnumerable<Student> GetAll()
{
return _studentRepository.GetAll().ToList();
}
}
Btw. this is absolutely useless code and example of silly layering which doesn't offer any useful functionality. Just wrapping the call to repository only shows that service is not needed at all as well as unit testing this method is not needed. The main point here is integration test for GetAll method.
Anyway if you want to unit thest such method with MOQ you will do:
[TestClass]
public class StudentsServiveTest
{
private Mock<IRespository<Student>> _repo;
[TestInitialize]
public void Init()
{
_repo = new Mock<IRepository<Student>>();
_repo.Setup(r => r.GetAll()).Returns(() => new Student[]
{
new Student { StudentId = 1, Name = "A", Surname = "B" },
new Student { StudentId = 2, Name = "B", Surname = "C" }
});
}
[TestMethod]
public void ShouldReturnAllStudents()
{
var service = new StudentsService(_repo.Object);
var data = service.GetAll();
_repo.Verify(r => r.GetAll(), Times.Once());
Assert.IsNotNull(data);
Assert.AreEqual(2, data.Count);
}
}
The issue from what I can see is that you are throwing away the mock object and newing up a new instance
_studentRepository = new StudentRepository(ctx);
Perhaps add a method on the interface to add the context object and reuse the same instance that was injected in the constructor.
using (var ctx = new SchoolContext("SchoolDB"))
{
_studentRepository.Context = ctx;
var students = _studentRepository.GetAll().ToList();
return students;
}
}
Not sure if it has been asked before, here is the question.
Code first:
public class Customer {
public string Password { get; set; }
public string PasswordHash { get; set; }
}
public class CustomerService {
private ICustomerRepository _repo;
public CustomerService(ICustomerRepository repo) {
_repo = repo;
}
public int? AddCustomer(Customer customer) {
customer.PasswordHash = SHA1Hasher.ComputeHash(customer.Password);
return _repo.Add(customer);
}
}
public interface ICustomerRepository {
int? Add(Customer c);
}
public class CustomerRepository : ICustomerRepository {
int? AddCustomer(Customer customer) {
// call db and return identity
return 1;
}
}
[TestClass]
public class CustomerServiceTest {
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving() {
var repoMock = new Mock<ICustomerRepository>();
//how do I make sure the password hash was calculated before passing the customer to repository???
}
}
How do I verify that CustomerService assigned the PasswordHash before passing the customer to repository?
There are several approaches you could take. Although not necessarily the best solution, here's one that doesn't require you to change your existing API. It assumes that SHA1Hasher.ComputeHash is a public method.
[TestClass]
public class CustomerServiceTest
{
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving()
{
var customer = new Customer { Password = "Foo" };
var expectedHash = SHA1Hasher.ComputeHash(customer.Password);
var repoMock = new Mock<ICustomerRepository>();
repoMock
.Setup(r => r.Add(It.Is<Customer>(c => c.PasswordHash == expectedHash)))
.Returns(1)
.Verifiable();
// invoke service with customer and repoMock.Object here...
repoMock.Verify();
}
}
A slightly better solution would be to turn the SHA1Hasher into an injected service (such as IHasher) so that you can confirm that the PasswordHash property was assigned the value created by the IHasher instance.
Opening op your API even more, you could make the PasswordHash property virtual, so that you could pass a Mock Customer to the AddCustomer method to verify that the property was correctly set.
You could make SHA1Hasher non-static and virtual or wrap it in a ISHA1Hasher interface which can then be mocked. Wrapping static methods and objects in mockable classes is a classic way to increase testability.