How to write a Unit testing for Azure Function app? - unit-testing

I have an azure function based on .Net core 3.1. It triggers when a file is uploaded into the Azure Blob Container, processes the CSV file and updates the database
Below is the code excerpt
FileTrigger.cs
namespace aspnetcore_azurefun_blob
{
[StorageAccount("AzureWebJobsStorage")]
public class FileTrigger
{
#region Property
private readonly IFileProcessor fileProcessor;
#endregion
#region Constructor
public FileTrigger(IFileProcessor fileProcessor)
{
this.fileProcessor = fileProcessor;
}
#endregion
[FunctionName("FileTrigger")]
public void ProcessFilesFromSamplesContainer([BlobTrigger("samples-workitems/{name}")]Stream myBlob, string name, ILogger log, ExecutionContext context)
{
log.LogInformation("Function: ProcessFilesFromSamplesContainer is called");
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
var result = fileProcessor.ProcessAsync(myBlob, name, log, context);
log.LogInformation($"Function Completed {result.Result} on {DateTime.Now.ToLongDateString()} # {DateTime.Now.ToShortTimeString()}.\n.");
}
}
}
FileProcessor.cs
namespace ClientCore.Processor
{
public interface IFileProcessor
{
Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context);
}
public class FileProcessor : IFileProcessor
{
#region Property
private readonly IFileProcessingServiceFacade fileProcessingService;
#endregion
#region Constructor
public FileProcessor(IFileProcessingServiceFacade fileProcessingService)
{
this.fileProcessingService = fileProcessingService;
}
#endregion
#region Public Methods
public async Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context)
{
var processingResult = fileProcessingService.ProcessAsync(myBlob, name, log, context);
return await Task.FromResult($"{processingResult.Result}");
}
#endregion
}
}
FileProcessingService.cs
namespace BusinessService.Services
{
public interface IFileProcessingServiceFacade
{
Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context);
}
partial class FileProcessingServiceFacade : IFileProcessingServiceFacade
{
#region Public Methods
public async Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context)
{
// Get the Contents from the CSV File
var csvData = GetCSVData(myBlob);
AppDbContext.FileRecords.Add(new FileRecords
{
FileName = name,
IsCompleted = DefaultValues.IsCompleted
});
AppDbContext.SaveChanges();
log.LogInformation($"Reading configuration from the configuration settings file: {Configurator.AzureSQLServerConfigurator.ConnnectionString}");
log.LogInformation("Database is updated..!");
return await Task.FromResult($"success");
}
#endregion
}
partial class FileProcessingServiceFacade : ServiceBase<FileProcessingServiceFacade>
{
#region Constructor
public FileProcessingServiceFacade(AppDbContext appDbContext, IOptions<AppConfigurator> configurator)
: base(appDbContext, configurator) { }
#endregion
#region Extract Data from CSV
protected static List<dynamic> GetCSVData(Stream jobData)
{
try
{
#region CsvHelper Mapping and Conversion
var csvHelperConfig = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
{
NewLine = Environment.NewLine,
PrepareHeaderForMatch = args => args.Header.ToUpper().Replace(" ", ""),
HasHeaderRecord = true
};
using var reader = new StreamReader(jobData);
using var csvHelper = new CsvReader(reader, CultureInfo.InvariantCulture);
csvHelper.Context.RegisterClassMap<StudentDetailsMap>();
var csvHelperRrecords = csvHelper.GetRecords<StudentDetails>()
.Where(x => !string.IsNullOrWhiteSpace(x.Name))
.OrderBy(x => x.ID);
return csvHelperRrecords.Cast<dynamic>().ToList();
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion
}
}
How to write a Unit testing for the above Azure Function app? Just a head start is required.

Related

How to unit test Durable Functions with CallActivityWithRetryAsync

I've read Microsoft documentation on Unit Testing
Unit testing: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-unit-testing
So for example, based on the MS documentation, if this is my orchestrator:
[FunctionName("SagaToTestOrchestrator")]
public static async Task<ShippingPrice> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var input = context.GetInput<SagaContext>();
RetryOptions _retryOptions = RetryConfiguration.GetActivityRetryOptions();
// activity to get proper orchestrator for continent for shipping partner
var supplierOrchestratorToRun = await context.CallActivityWithRetryAsync<string>("GetSupplierOrchestratorForContinent", _retryOptions, input.Continent);
// orchestrator to get the price for the shipping address
var priceForShipment =
await context.CallSubOrchestratorAsync<decimal>($"{supplierOrchestratorToRun}Orchestrator", input);
// activity to publish event for Sales / marketing
await context.CallActivityWithRetryAsync("PublishCalculatedPriceActivity", _retryOptions,(input, priceForShipment));
return new ShippingPrice()
{
Shippable = true,
Price = priceForShipment
};
}
[FunctionName("CourierAOrchestrator")]
public static async Task<decimal> CourierAOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
{
return 100;
}
[FunctionName("CourierBOrchestrator")]
public static async Task<decimal> CourierBOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
{
return 120;
}
[FunctionName("IsContinentSupported")]
public static async Task<bool> IsContinentSupported([ActivityTrigger] string continent, ILogger log)
{
var supportedContinents = new List<string>
{
"North America", "South America", "Europe",
};
return supportedContinents.Contains(continent);
}
[FunctionName("GetSupplierOrchestratorForContinent")]
public static async Task<string> GetSupplierOrchestratorForContinent([ActivityTrigger] string continent, ILogger log)
{
var courier = "";
switch (continent)
{
case "South America":
case "North America":
courier = "CourierA";
break;
case "Europe":
courier = "CourierB";
break;
}
return courier;
}
[FunctionName("PublishCalculatedPriceActivity")]
public static async Task PublishCalculatedPriceActivity([ActivityTrigger] (SagaContext context, decimal price) input, ILogger log)
{
log.LogInformation($"{input.context.Continent}: {input.price}");
}
public class ShippingPrice
{
public bool Shippable { get; set; }
public decimal Price { get; set; }
public string Message { get; set; }
}
public class SagaContext
{
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Continent { get; set; }
}
And my test would be something like this:
public async Task CalculatePriceForAmerica()
{
// Arrange / Given
var orchContext = new SagaContext
{
Continent = "North America"
};
var context = new Mock<IDurableOrchestrationContext>();
// mock the get input
context.Setup(m =>
m.GetInput<SagaContext>()).Returns(orchContext);
// set-up mocks for activity
context.Setup(m
=> m.CallActivityWithRetryAsync<string>("GetSupplierOrchestratorForContinent", _retryOptions, It.IsAny<object>()))
.ReturnsAsync("CourierA");
// set-up mocks for suborchstrators
context.Setup(m =>
m.CallSubOrchestratorAsync<decimal>("CourierAOrchestrator", It.IsAny<string>(), It.IsAny<object>()))
.ReturnsAsync(100);
// ACT / When
var price = await SagaToTestOrchestrator.RunOrchestrator(context.Object);
// Assert / Then
Assert.True(price.Shippable);
Assert.Equal(100, price.Price);
}
Here the issue I am facing is
setup mock data for the GetSupplierOrchestratorForContinent Activity , so ideally it should return "CourierA" as output when the actual Orchestrator method is called but it is returning null.

ContosoUniversityDotNetCore-Pages SliceFixture with AutoMapper

My Create handler uses AutoMapper to map from command to entity.
public async Task<int> Handle(Command command, CancellationToken cancellationToken)
{
var entity = _mapper.Map<ExampleEntity>(command);
await _db.ExampleEntity.AddAsync(entity, cancellationToken);
await _db.SaveChangesAsync(cancellationToken);
return entity.Id;
}
My test looks like this
var command = new Create.Command
{
Name = "Example 1",
...
};
var id = await _fixture.SendAsync(command, mapper);
id.ShouldNotBeNull();
This is the SliceFixture
[CollectionDefinition(nameof(SliceFixture))]
public class SliceFixtureCollection : ICollectionFixture<SliceFixture> { }
public class SliceFixture : IAsyncLifetime
{
private readonly Checkpoint _checkpoint;
private readonly IConfiguration _configuration;
private readonly IServiceScopeFactory _scopeFactory;
private readonly WebApplicationFactory<Startup> _factory;
public SliceFixture()
{
_factory = new ContosoTestApplicationFactory();
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
_scopeFactory = _factory.Services.GetRequiredService<IServiceScopeFactory>();
_checkpoint = new Checkpoint();
}
public class ContosoTestApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((_, configBuilder) =>
{
configBuilder.AddInMemoryCollection(new Dictionary<string, string>
{
{"ConnectionStrings:DefaultConnection", _connectionString}
});
});
}
private readonly string _connectionString = "";
}
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
{
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<SchoolContext>();
try
{
await dbContext.BeginTransactionAsync();
await action(scope.ServiceProvider);
await dbContext.CommitTransactionAsync();
}
catch (Exception)
{
dbContext.RollbackTransaction();
throw;
}
}
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
{
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<SchoolContext>();
try
{
await dbContext.BeginTransactionAsync();
var result = await action(scope.ServiceProvider);
await dbContext.CommitTransactionAsync();
return result;
}
catch (Exception)
{
dbContext.RollbackTransaction();
throw;
}
}
public Task ExecuteDbContextAsync(Func<SchoolContext, Task> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>()));
public Task ExecuteDbContextAsync(Func<SchoolContext, ValueTask> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>()).AsTask());
public Task ExecuteDbContextAsync(Func<SchoolContext, IMediator, Task> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>(), sp.GetService<IMediator>()));
public Task<T> ExecuteDbContextAsync<T>(Func<SchoolContext, Task<T>> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>()));
public Task<T> ExecuteDbContextAsync<T>(Func<SchoolContext, ValueTask<T>> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>()).AsTask());
public Task<T> ExecuteDbContextAsync<T>(Func<SchoolContext, IMediator, Task<T>> action) => ExecuteScopeAsync(sp => action(sp.GetService<SchoolContext>(), sp.GetService<IMediator>()));
public Task InsertAsync<T>(params T[] entities) where T : class
{
return ExecuteDbContextAsync(db =>
{
foreach (var entity in entities)
{
db.Set<T>().Add(entity);
}
return db.SaveChangesAsync();
});
}
public Task<T> FindAsync<T>(int id)
where T : class, IEntity
{
return ExecuteDbContextAsync(db => db.Set<T>().FindAsync(id).AsTask());
}
public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
public Task SendAsync(IRequest request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
private int _courseNumber = 1;
public int NextCourseNumber() => Interlocked.Increment(ref _courseNumber);
public Task InitializeAsync() => _checkpoint.Reset(_configuration.GetConnectionString("DefaultConnection"));
public Task DisposeAsync()
{
_factory?.Dispose();
return Task.CompletedTask;
}
}
When I run the test I get -
Object reference not set to an instance of an object.
because _mapper is null.
I know I probably need to modify the SliceFixture but can't figure out what to do.
I was looking to implement Jimmy’s example here with the additional AutoMapper implementation.

.net core xunit How verify if method was called from inherited class

I have a base class called BaseService, and i want to verify if method IsValid was called in my unit test.
public interface IBaseService
{
bool IsValid<Dto, DtoValidator>(Dto entityDto, DtoValidator validator) where DtoValidator : AbstractValidator<Dto>;
}
public class BaseService : IBaseService
{
protected readonly IMapper _mapper;
protected readonly INotificationService _notification;
public BaseService(
IMapper mapper,
INotificationService notification)
{
_mapper = mapper;
_notification = notification;
}
public virtual bool IsValid<Dto, DtoValidator>(Dto entityDto, DtoValidator validator) where DtoValidator : AbstractValidator<Dto>
{
var result = validator.Validate(entityDto);
foreach (var error in result.Errors)
{
_notification.Notify(error.ErrorMessage);
}
return result.IsValid;
}
}
Class that use BaseService , some parts of code was omited
public interface IAfiliadoService : IBaseService {}
public class AfiliadoService : BaseService, IAfiliadoService
{
public AfiliadoService(
IMapper mapper,
INotificationService notification) : base(mapper, notification)
{
_afiliadoRepository = afiliadoRepository;
_lojaRepository = lojaRepository;
}
public async Task<AfiliadoResponseDto> AddAsync(AddAfiliadoRequestDto request)
{
if (IsValid(request, new AddAfiliadoRequestDtoValidator()))
{
}
}
}
In my test project i created those classes
public class MockBaseService
{
public readonly Mock<IMapper> _mapper;
public readonly Mock<INotificationService> _notification;
public MockBaseService()
{
_mapper = new Mock<IMapper>();
_notification = new Mock<INotificationService>();
}
}
public class AfiliadoServiceTest : MockBaseService
{
private readonly IAfiliadoService _afiliadoService;
public AfiliadoServiceTest()
{
_afiliadoService = new AfiliadoService(
_mapper.Object,
_notification.Object);
}
[Fact]
public async Task AdicionarUsuarioComEmailQueJaExisteDeveNotificar()
{
var request = new AddAfiliadoRequestDto();
var result = await _afiliadoService.AddAsync(request);
Assert.Null(result);
_notification
.Verify(v => v.Notify(It.IsAny<string>()), Times.Once);
// Here i want verify if method IsValid was called Once, like the verification above
}
}
I tried some things but with no success.
Exemple with what i want.
var mock = new Mock<AfiliadoService>();
mock.Verify(v => v.IsValid(request, new AddAfiliadoRequestDtoValidator()), Times.Once);
var mock = new Mock<AfiliadoService>(_mapper.Object,
_notification.Object);
var result = await mock.Object.AddAsync(request);
mock.Verify(v => v.IsValid(request, new AddAfiliadoRequestDtoValidator()), Times.Once);
This last one i got the message
Message:
Moq.MockException :
Expected invocation on the mock once, but was 0 times: v => v.IsValid<AddAfiliadoRequestDto, AddAfiliadoRequestDtoValidator>(AddAfiliadoRequestDto, AddAfiliadoRequestDtoValidator)
Performed invocations:
Mock<AfiliadoService:1> (v):
BaseService.IsValid<AddAfiliadoRequestDto, AddAfiliadoRequestDtoValidator>(AddAfiliadoRequestDto, AddAfiliadoRequestDtoValidator)
What im doing wrong?
Im using .net core - 3.1
xunit - 2.4.1
Moq - 4.16.0

Unable to resolve service for type 'Api.Repositories.UnitOfWork' while attempting to activate 'Api.ServicesBusiness.EquipoServices'

I want to make a webapi and I'm trying to do it through the services way, I have a repository generic and another 2 repository and a unit of work, apparently everything goes fine, but when I run and test the webapi from postman I got that error:
InvalidOperationException: Unable to resolve service for type 'Api.Repository.Repositories.UnitOfWork' while attempting to activate 'Api.ServicesBusiness.Implementacion.EquipoServices'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
Here is the my dbcontect:
public class AppDbContext : DbContext
{
public AppDbContext()
{
}
public AppDbContext(DbContextOptions<AppDbContext> option) :base(option)
{
}
public DbSet<Equipo> Equipos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\Express;Database=SoftballLeague;Trusted_Connection=True");
}
}
}
Here is the interface of my generic repository:
public interface IGenericRepository<T> where T : class
{
Task<T> AddAsyn(T t);
Task<T> UpdateAsyn(T t, object key);
}
Here is the implementation of my generic repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly AppDbContext _context;
private readonly DbSet<T> _dbSet;
public GenericRepository(AppDbContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
public virtual async Task<T> AddAsyn(T t)
{
_dbSet.Add(t);
await _context.SaveChangesAsync();
return t;
}
public virtual async Task<T> UpdateAsyn(T t, object key)
{
if (t == null)
return null;
T exist = await _dbSet.FindAsync(key);
if (exist != null)
{
_context.Entry(exist).CurrentValues.SetValues(t);
await _context.SaveChangesAsync();
}
return exist;
}
}
Here is the interface of my equipo repository:
public interface IEquipoRepository:IGenericRepository<Team>
{
int GetAverageTeam(string name);
int GetTeamHit(string name);
}
Here is the implementation of my equipo repository:
public class EquipoRepository : GenericRepository<Team>, IEquipoRepository
{
private readonly AppDbContext dbContext;
public EquipoRepository(AppDbContext context) : base(context)
{
this.dbContext = context;
}
public int GetAverageTeam(string name)
{
int teamAverage = 0;
var resultAverage = this.dbContext.Equipos
//.SelectMany(bItem => bItem.)
.Where(equipo=>equipo.Nombre==name)
.SelectMany(equipo => equipo.jugadores)
.Average(jugador => jugador.Average);
if (resultAverage.HasValue)
teamAverage =Convert.ToInt32(Math.Round(resultAverage.Value));
return teamAverage;
}
public int GetTeamHit(string name)
{
int resultTotal = 0;
var result = this.dbContext.Equipos
//.SelectMany(bItem => bItem.)
.Where(equipo => equipo.Nombre == name)
.SelectMany(equipo => equipo.jugadores)
.Sum(jugador => jugador.Cant_Hits_Conectados);
if (result.HasValue)
resultTotal = result.Value;
return resultTotal;
}
}
Here is the interface of my unit of work:
public interface IUnitOfWork:IDisposable
{
Task Commit();
}
Here is the implementation of my unit of work:
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _DbContext;
private EquipoRepository equipoRepository ;
public UnitOfWork(AppDbContext dbContext)
{
this._DbContext = dbContext;
this.equipoRepository = new EquipoRepository(this._DbContext);
}
public EquipoRepository GetEquipoRepository{
get {
if(this.equipoRepository==null)
this.equipoRepository= new EquipoRepository(this._DbContext);
return this.equipoRepository;
}
}
public async Task Commit()
{
await this._DbContext.SaveChangesAsync();
}
public void Dispose()
{
this._DbContext.Dispose();
}
}
Here is the implementation of services interfaces IEquipoServices:
public interface IEquipoServices
{
ICollection<EstadisticaEquipoModel>AveragePorEquipo(string name);
int Total2bleConectados(string name);
}
Here is the implementation of services EquipoServices which is the one who throws the error:
public class EquipoServices : IEquipoServices
{
private readonly UnitOfWork unit;
public EquipoServices(UnitOfWork unitOfWorkFactory)
{
this.unit = unitOfWorkFactory;
}
public ICollection<EstadisticaEquipoModel> AveragePorEquipo(string name)
{
var equipoAverage= this.unit.GetEquipoRepository.GetAverageEquipo(name);
return equipoAverage;
}
public int AveragePorEquipo(string name)
{
var result = this.unit.GetEquipoRepository.GetEquipoTotal2bleConectados(name);
return result;
}
}
This is the controller, here I am just running the ListadoEquipos() method:
[Route("api/[controller]")]
public class EquipoController : ControllerBase
{
private readonly IEquipoServices equipoService;
private readonly IMapper _mapper;
public EquipoController(IEquipoServices eqService, IMapper mapper)
{
this.equipoService = eqService;
this._mapper = mapper;
}
[HttpGet("list")]
public IEnumerable<string> ListadoEquipos()
{
return new string[] { "value1", "value2" };
}
}
This is the configuration in the startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options=>options.UseSqlServer(Configuration.GetConnectionString("ConnectionString")));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddSingleton<IEquipoServices, EquipoServices>();
//services.AddScoped<IJu, JugadorService>();
services.AddAutoMapper(typeof(Startup));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
You registered IUnitOfWork, but you're injecting UnitOfWork. The service collection doesn't know how to inject UnitOfWork directly.
Long and short, inject IUnitOfWork instead:
private readonly IUnitOfWork unit;
public EquipoServices(IUnitOfWork unitOfWorkFactory)

ASP.NET MVC unit testing with MOQ object

What is the best way to mock below code in unit testing:
public ActionResult Products()
{
ViewBag.Title = "Company Product";
IEnumerable<ProductDetailDto> productList = ProductService.GetAllEffectiveProductDetails();
ProductModels.ProductCategoryListModel model = new ProductModels.ProductCategoryListModel
{
//the type of ProductDetails => IEnumerable<productDetailDto>
ProductDetails = ProductService.GetAllEffectiveProductDetails(),
//the type of ProductCategoryList => IEnumerable<selectlistitem>
ProductCategoryList = productList.Select(x => new SelectListItem
{
Value = x.FKProductId.ToString(),
Text = x.Name
})
};
return View(model);
}
FYI, I am working on VS 2012, MVC 4.0, Unit Testing with MOQ object and TFS setup.
Can anyone help me out on this what is the best test method with mock object for above method?
If you want to mock ProductService first you need to inject this dependency.
Constructor injection is the most common approach for controllers in ASP.NET MVC.
public class YourController : Controller
{
private readonly IProductService ProductService;
/// <summary>
/// Constructor injection
/// </summary>
public YourController(IProductService productService)
{
ProductService = productService;
}
/// <summary>
/// Code of this method has not been changed at all.
/// </summary>
public ActionResult Products()
{
ViewBag.Title = "Company Product";
IEnumerable<ProductDetailDto> productList = ProductService.GetAllEffectiveProductDetails();
ProductModels.ProductCategoryListModel model = new ProductModels.ProductCategoryListModel
{
//the type of ProductDetails => IEnumerable<productDetailDto>
ProductDetails = ProductService.GetAllEffectiveProductDetails(),
//the type of ProductCategoryList => IEnumerable<selectlistitem>
ProductCategoryList = productList.Select(x => new SelectListItem
{
Value = x.FKProductId.ToString(),
Text = x.Name
})
};
return View(model);
}
}
#region DataModels
public class ProductDetailDto
{
public int FKProductId { get; set; }
public string Name { get; set; }
}
public class ProductModels
{
public class ProductCategoryListModel
{
public IEnumerable<ProductDetailDto> ProductDetails { get; set; }
public IEnumerable<SelectListItem> ProductCategoryList { get; set; }
}
}
#endregion
#region Services
public interface IProductService
{
IEnumerable<ProductDetailDto> GetAllEffectiveProductDetails()
}
public class ProductService : IProductService
{
public IEnumerable<ProductDetailDto> GetAllEffectiveProductDetails()
{
throw new NotImplementedException();
}
}
#endregion
Then you easily create a mock instance of IProductService, pass it into constructor of YourController, setup GetAllEffectiveProductDetails method and check returned ActionResult and its model.
[TestClass]
public class YourControllerTest
{
private Mock<IProductService> productServiceMock;
private YourController target;
[TestInitialize]
public void Init()
{
productServiceMock = new Mock<IProductService>();
target = new YourController(
productServiceMock.Object);
}
[TestMethod]
public void Products()
{
//arrange
// There is a setup of 'GetAllEffectiveProductDetails'
// When 'GetAllEffectiveProductDetails' method is invoked 'expectedallProducts' collection is exposed.
var expectedallProducts = new List<ProductDetailDto> { new ProductDetailDto() };
productServiceMock
.Setup(it => it.GetAllEffectiveProductDetails())
.Returns(expectedallProducts);
//act
var result = target.Products();
//assert
var model = (result as ViewResult).Model as ProductModels.ProductCategoryListModel;
Assert.AreEqual(model.ProductDetails, expectedallProducts);
/* Any other assertions */
}
}