Moq: setup a generic method with mocked parameters - c#

I've been trying to write a few tests in NUnit for my generic methods, without success. I hope I can make my situation clear, since I had to heavily paraphrase my code.
DoBusinessLogic() is the method I want to test. It calls two other methods from the base class:
public class MySvc : BaseSvc, IMySvc
{
private readonly IMyRepo _repo;
private readonly IMyConnectorClass _connector
public MySvc(IMyRepo repo) : base(repo)
{
_repo = repo;
_connector = _repo.GetConnector();
}
public async Task DoBusinessLogic(int id1, int id2){
bool doesFirstObjectExist = await CheckMainObjExists<Foo>(id1, _connector);
await CheckSubObjExists<Bar>(id2, _connector);
// further business logic
}
}
Those methods, in turn, call the same repository method, but have different logic after it:
public abstract class BaseSvc : IBaseSvc
{
private readonly IBaseRepo _repo
protected BaseSvc(IBaseRepo repo)
{
_repo = repo;
}
protected async Task<bool> CheckMainObjExists<T>(int? id, IMyConnectorClass connector)
{
return await _repo.GetObjectByIdAsync<T>(Id, connector) != null;
}
protected async Task CheckSubObjExists<T>(int? id, IMyConnectorClass connector)
{
if (await _repo.GetObjectByIdAsync<T>(Id, connector) == null)
{ throw new Exception("Object not found!"); }
}
}
Next, I want to write unit a test for DoBusinessLogic() in the MySvc class. Unfortunately, it seems I can't mock the responses from the repository.
[TestFixture]
public class MySvcTests
{
private MySvc _svc;
private Mock<IMyRepo> _repoMock;
private Mock<IMyConnectorClass> _connectorMock;
[SetUp]
public void SetUp()
{
_repoMock = new Mock<IMyRepo>() {};
_connectorMock = new Mock<IMyConnectorClass>();
_repo.SetUp(r => r.GetConnector()).Return(_connectorMock.Object);
_svc = new MySvc(_repoMock);
}
/*
My intent in this test, is to make CheckMainObjExists() pass,
but make CheckSubObjExist() fail.
*/
[Test]
public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException()
{
// This should return an object
_repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync(new Foo());
// This should return null
_repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync((Bar) null);
Assert.Throws<Exception>(await _svc.DoBusinessLogic());
}
}
However, when I run the test, both methods that I set up for my mock repo return null, whereas I expect a "true" from the first.
I do not know where the problem is situated, but I have my suspicions:
Is it possible to setup a method, using a mocked object as a parameter? In this case, is it possible to use _connectorMock.Object as a setup parameter?
Is it possible to setup the same generic method multiple times, but for a different type each time? It's first setup for Foo, then for Bar.

I just tested this code and it runs as expected. Now I had to make a lot of assumptions just to get the code to compile and run which would mean that my test of your code is flawed as I may have fixed something that was omitted in your example.
I made no changes to your test setup code, which worked.
[TestClass]
public class MySvcTests {
[TestMethod]
[ExpectedException(typeof(Exception))]
public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException() {
var _repoMock = new Mock<IMyRepo>() { };
var _connectorMock = new Mock<IMyConnectorClass>();
_repoMock.Setup(r => r.GetConnector()).Returns(_connectorMock.Object);
var _svc = new MySvc(_repoMock.Object);
// This should return an object
_repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync(new Foo());
// This should return null
_repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync((Bar)null);
await _svc.DoBusinessLogic(0, 0);
}
}

Related

How to seed data only once before running all tests using MSTest

I have bunch of tests class such as CustomerTest, ProductTest, VendorTest and so on. I'm using in-memory Database and I would like to seed all data that I need to ONLY ONCE before running all these Tests above but have no idea how to do it.
I have CustomWebApplicationFactory class
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<Program>
{
public ApplicationContext context { get; set; }
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services => {
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ApplicationContext>));
if (descriptor != null)
services.Remove(descriptor);
services.AddDbContext<ApplicationContext>(options => options
.UseInMemoryDatabase("testDB")
);
var serviceProvider = services.BuildServiceProvider();
using (var scope = serviceProvider.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationContext>();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
SeedData(db); //seeding all data to all table
}
});
}
}
My Tests class
[TestClass]
public class VendorTest : BaseTest
{
[TestMethod]
public async Task AddVendor()
{
var content = JsonSerializer.Serialize(
new
{
name = "VENDORTEST"
}
);
var response = await _httpClient.PostAsync(
"vendors",
new StringContent(content, Encoding.UTF8, "application/json")
);
Assert.IsTrue(response.IsSuccessStatusCode);
}
[TestMethod]
public async Task GetVendor()
{
var response = await _httpClient.GetAsync("vendors");
string result = await response.Content.ReadAsStringAsync();
Assert.IsNotNull(response);
}
}
Base Test
public class BaseTest
{
protected static CustomWebApplicationFactory<Program> _webAppFactory = new CustomWebApplicationFactory<Program>();
protected static HttpClient _httpClient = _webAppFactory.CreateDefaultClient();
[AssemblyInitialize]
public void Initialize()
{
//not sure if BaseClass is the way to do it
//_httpClient = _webAppFactory.CreateDefaultClient();
}
}
Everytime a TestMethod is running, it will reseed all of the data due to CustomWebApplicationFactory. Any idea how to do it only once?
First of all: I dislike your idea so much, that I hesitated to show you a possible approach. I'll explain that after the code.
If you need something, that runs only once, static things come to mind. So, you could use a static/singleton factory to create your in-memory database like this:
public class TestDbFactory
{
private static TestDbFactory instance;
private readonly ApplicationContext applicationContext;
private TestDbFactory()
{
var databaseName = Guid.NewGuid().ToString();
var inMemoryContextOptions = new DbContextOptionsBuilder<ApplicationContext>()
.UseInMemoryDatabase(databaseName)
.Options;
this.applicationContext = new ApplicationContext(inMemoryContextOptions);
this.InitDatabase();
}
public static TestDbFactory Instance => CreateOrReuseInstance();
public ApplicationContext ApplicationContext => this.applicationContext;
private static TestDbFactory CreateOrReuseInstance()
{
if (instance != null) return instance;
var semaphore = new SemaphoreSlim(1, 1);
instance = instance ?? new TestDbFactory();
semaphore.Release(1);
return instance;
}
private void InitDatabase()
{
// ensure deleted & created & seeded for this.applicationContext
}
}
Now you can either use TestDbFactory.Instance.ApplicationContext to pass the database to the systems under test or you can use the factory pattern of the dependency injection setup to provide the context:
services.AddScoped(_ => TestDbFactory.Instance.ApplicationContext);
What I don't like about your idea:
Even for a single test you have to seed the whole database.
You can't do write test, because then tests don't have a predictable setup (it might be or not, that the db contents have changed before a test runs).
To me a test also serves as documentation. This is not possible, if the database content relevant for a specific test can't be determined from the test.
Adding new tests and updating the seeding will become a nightmare as you (let alone a whole team) have to verify the new data vs. all existing tests.
You won't save much typing as you still have to data for every test.
So, to me a better approach would be to use an in-memory database in every test class (a test class contains all tests for a single method). It would be ok to provide a basic seeding common to all tests in the test class, but specific data setup for a test should go with the test.
I hope that this post helps in one way or the other.

Mocked method do not pass correct value

I am trying to understand how mocking works in Xunit with AutoFixture. I have created Service and Repository classes and their interfaces. Mocked method should pass value which is different from default value.
Mocked method always pass default values instead of values which i am writing in ".Returns()". I have tried AutoConfiguredMoqCustomization but it provides completely random values which i can't get back.
Repository.cs
public class Repository : IRepository
{
public int GetInt()
{
return 999;
}
}
Service.cs
public class Service : IService
{
private readonly Repository _repository;
public Service()
{
_repository = new Repository();
}
public string GetStringFromInt()
{
return _repository.GetInt().ToString();
}
}
Test
[Fact]
public void Test()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var repositoryMock = fixture.Create<Mock<IRepository>>();
var service = fixture.Create<Service>();
repositoryMock.Setup(x => x.GetInt()).Returns(1);
var act = service.GetStringFromInt();
Assert.Equal("1", act);
}
As you see value by default in Repository is 999 and I am expecting 1 from repositoryMock but result is "999" instead of "1".
Ow I have understood my problem. When I declare parameters with auto moq testing service must be AFTER all mocked repositories
Test
[Theory, AutoMoqData]
public void Test([Frozen] Mock<IRepository> repositoryMock, Service service)
{
...
}
Attribute
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(GetDefaultFixture)
{
}
private static IFixture GetDefaultFixture()
{
return new Fixture().Customize(new AutoMoqCustomization());
}
}
You should freeze your mock first. When you call Create on AutoFixture, it will create you a new instance every time. Try the following in the modified code (where you are using an interface of the type in your constructor).
public class ServiceTests
{
private readonly IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
public ServiceTests()
{
fixture.Register<IService>(() => fixture.Create<Service>());
}
[Fact]
public void Test()
{
// Arrange
var repositoryMock = fixture.Freeze<Mock<IRepository>>();
repositoryMock.Setup(x => x.GetInt()).Returns(1);
var service = fixture.Create<IService>();
// Act
var act = service.GetStringFromInt();
// Verify
Assert.Equal("1", act);
}
}
To check that you have set up autofixture correctly, you can try the following in the unit test in future.
var repo1 = fixture.Create<IRepository>();
var repo2 = fixture.Create<IRepository>();
Assert.Equal(repo1.GetHashCode(), repo2.GetHashCode());
If the above fails, that indicates that you have not frozen a type. These lines of code have saved me so much head scratching in the past...
You are doing DI wrong, you are not injecting Repository into Your serice.
Try like this.
public class Repository : IRepository
{
public int GetInt()
{
return 999;
}
}
public class Service : IService
{
IRepository Repository;
public Service(IRepository repository)
{
this.Repository = repository;
}
public string GetStringFromInt()
{
return Repository.GetInt().ToString();
}
}
Now when you mock IRepository, you can add it to Service.
You are using a new Repository() in constructor, so you are using that implementation

I want to Create Xunit test for this controller. How can i do that

I have created small kind of xunit test case but I don't know how to create this controller which i have mention below.
public class PropertyController : ControllerBase
{
private readonly IMediator _mediator;
private readonly ILogger<PropertyController> _logger;
public PropertyController(IMediator mediator, ILogger<PropertyController> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<IActionResult> AddProperty([FromBody] AddPropertyCommand command)
{
bool commandResult = false;
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({#Command})",
command.GetGenericTypeName(),
nameof(command.ModifiedUserId),
command.ModifiedUserId,
command);
commandResult = await _mediator.Send(command);
if (!commandResult)
{
return BadRequest();
}
return Ok();
}
I have created like this. i have mock the dependency and create a test case for add command is working fine or not
public class PropertyControllerTest
{
private readonly PropertyController _it;
private readonly Mock<IMediator> _mediatorMock;
private readonly Mock<ILogger<PropertyController>> _loggerPropertycontrollerMock;
public PropertyControllerTest()
{
_mediatorMock = new Mock<IMediator>();
_loggerPropertycontrollerMock = new Mock<ILogger<PropertyController>>();
_it = new PropertyController(_mediatorMock.Object, _loggerPropertycontrollerMock.Object);
}
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
//How can i write xunit test case. I'm creating like this
_mediatorMock.Setup(x => x.Send().Returns(property);
}
The test below covers the 200 status result - a similar test for bad requests would be very similar.
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
// Arrange
var expected = new AddPropertyCommand();
_mediatorMock.Setup(x => x.Send(It.IsAny<AddPropertyCommand>())).Returns(true);
// Act
var actionResult = _it.AddProperty(expected);
// Assert
actionResult.ShouldBeAssignableTo<OkResult>();
_mediatorMock.Verify(x => x.Send(expected));
}
N.B. actionResult.ShouldBeAssignableTo<OkResult>(); is written using the Shouldly assertion framework, you can swap that out for anything you like. The one built into XUnit would be like this: Assert.IsType(typeof(OkResult), actionResult);

xUnit test asp net core Mapper not initialized

I am testing this method that in the end does mapping to my DTO
public async Task<IActionResult> Get()
{
var currencies = await _repository.GetCurrencies().ToListAsync().ConfigureAwait(false);
if (currencies.Count == 0)
return NoContent();
return Ok(currencies.ToDto());
}
In return of this method I get the following error:
Message: System.InvalidOperationException : Mapper not initialized.
Call Initialize with appropriate configuration. If you are trying to
use mapper instances through a container or otherwise, make sure you
do not have any calls to the static Mapper.Map methods, and if you're
using ProjectTo or UseAsDataSource extension methods, make sure you
pass in the appropriate IConfigurationProvider instance.
I use a static method to do auto mapper
public static List<CurrencyDTO> ToDto(this List<Currency> model)
{
return Mapper.Map<List<Currency>, List<CurrencyDTO>>(model);
}
When I run only this test it passes but when I squeeze everyone it speaks
I tried already make a builder initialize mapper but continue error, test only passes if it is run individually
public class CurrenciesControllerTest
{
public CurrenciesControllerTest()
{
AutoMapperConfig.RegisterMappings();
}
private Mock<IReimbursementRepository> _repository = new Mock<IReimbursementRepository>();
[Fact]
public async Task Should_return_all_currencies()
{
var mock = Currencyfactory().AsQueryable().BuildMock();
_repository.Setup(x => x.GetCurrencies()).Returns(mock.Object);
var controller = new CurrenciesController(_repository.Object);
var response = await controller.Get().ConfigureAwait(false) as OkObjectResult;`enter code here`
Assert.Equal(response.StatusCode, (int)HttpStatusCode.OK);
}
}
my solution, configure AutoMapperConfig
public class AutoMapperConfig
{
public static object thisLock = new object();
public static void Initialize()
{
lock (thisLock)
{
AutoMapper.Mapper.Reset();
AutoMapper.Mapper.Initialize(cfg => { });
}
}
}
}

Cannot instantiate proxy of class error

I am doing a simple unit test where when creating a Course, the Title field cannot be empty. I am having to test it with a service class that has Dependency Injection with UnitOfWork. When I debug my test, I am getting an Exception error of Can not instantiate proxy of class: ContosoUniversity.Models.CourseRepository I looked into the error, but am not able to understand how to fix the issue and the Assert statement?
Error Message Display Image
CourseRepository
public class CourseRepository : GenericRepository<Course>
{
public CourseRepository(SchoolContext context)
: base(context)
{
}
UnitOfWork
public class UnitOfWork : IDisposable, IUnitOfWork
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
}
public virtual CourseRepository GetCourseRepository()
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
CourseService
public class CourseService : ICourseService
{
private IUnitOfWork unitOfWork;
public CourseService (IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
public void Create(Course course)
{
unitOfWork.GetCourseRepository().Insert(course);
unitOfWork.Save();
}
public Course GetCourseByID(int id)
{
return unitOfWork.GetCourseRepository().GetByID(id);
}
TestMethod
[TestMethod]
public void TestMethod1()
{
var course = new Course
{
CourseID = 2210,
Title = string.Empty,
Credits = 3,
DepartmentID = 1
};
Mock<CourseRepository> mockRepo = new Mock<CourseRepository>();
mockRepo.Setup(m => m.GetByID(course.CourseID)).Returns(course);
var mockUnit = new Mock<IUnitOfWork>();
mockUnit.Setup(x => x.GetCourseRepository()).Returns(mockRepo.Object);
var myService = new CourseService(mockUnit.Object);
myService.Create(course);
//var error = _modelState["Title"].Errors[0];
//Assert.AreEqual("The Title field is required.", error.ErrorMessage);
//mockRepo.Setup(x => x.Insert(course));
}
The error says that the CourseRepository can not be initialized because it does not have parameter less constructor. Mocking framework looks for parameter less constructor first to create mock object.
If your class does not have parameterless constructor then you need to pass those parameters when you create Mock. In your case mock of CourseRepository would be created as following.
var repositoryMock = new Mock<CourseRepository>(null);
Instead of null, you can pass mock objects of the constructor parameters also.
Just use the interface when mocking.
Mock<ICourseRepository> mockRepo = new Mock<ICourseRepository>();
mockRepo.Setup(m => m.GetByID(course.CourseID)).Returns(course);
Alternatively, if your class has an internal parameterless constructor, you need to add the InternalsVisibleTo attribute to assembly.
In case of Moq, add this:
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
Or this, if you need an strong key
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
In my case, adding the [Frozen] attribute to my mock helped solve this problem.
I was also having the "cannot instantiate proxy of class error", but in my case, I was doing something like this:
[Theory, AutoMoqDate]
public async void Should_DoThis_When_ThatHappens(
Fixture fixture,
Mock<TroublesomeClass> troublesomeObject
){
var someResult = SomeObject();
troublesomeObject.Setup(o => o.SomeMethodAsync().ReturnsAsync(someResult);
// Code bellow is irrelevant...
}
For me, troublesomeObject's method was called in my suite's method, and when it got to SomeMethodAsync() is when the exception occurred.
When I added the [Frozen] tag before the troublesome object, the issue subsided.

Categories

Resources