I am trying to write a unit test but encountered a strange problem
[TestMethod]
public void Delete_user_save_via_context()
{
var data = new List<admins>
{
new admins() {id = 1, login = "test" },
}.AsQueryable();
var mockSet = new Mock<DbSet<admins>>(data);
mockSet.As<IQueryable<admins>>().Setup(x => x.Provider).Returns(data.Provider);
mockSet.As<IQueryable<admins>>().Setup(x => x.Expression).Returns(data.Expression);
mockSet.As<IQueryable<admins>>().Setup(x => x.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<admins>>().Setup(x => x.GetEnumerator()).Returns(data.GetEnumerator);
var mockContext = new Mock<Entities>();
mockContext.Setup(x => x.admins).Returns(mockSet.Object); //Here i have Exception
var userService = new UserService(mockContext.Object);
userService.Delete("test");
mockSet.Verify(m => m.Remove(It.IsAny<admins>()),Times.Once);
mockContext.Verify(m => m.SaveChanges(), Times.Once);
}
This throws exception :
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException: Can not
instantiate proxy of class: Could not find a constructor that would
match given arguments: System.Linq.EnumerableQuery`
Can somebody help with this ?
Implementation of admin class :
public partial class admins
{
public int id { get; set; }
public string login { get; set; }
}
var mockSet = new Mock<DbSet<admins>>(data);
Should be:
var mockSet = new Mock<DbSet<admins>>();
Related
So I've trying to test my webapp coded in .net core 5.0, and I have a classic MVC model with service classes. Now I am trying to unit test the solution with moq to mock my database, and my tests run, but I have just noticed that they are all wrong when I debug. It seems as if it doesn't actually connect to the mock service or database itself... I have gone for mocking the service interface but that doesn't seem to work still. Help would be greatly appreciated.
Service class:
public class InventoryService : IInventoryService
{
private readonly DBContext _db;
public InventoryService(DBContext db)
{
_db = db;
}
public List<Inventory> GetInventories(string id)
{
var inventories = (from i in _db.Inventories where i.userId.Equals(id) select i).ToList();
return inventories;
}
public void CreateInventory(Inventory newInventory)
{
_db.Inventories.Add(newInventory);
_db.SaveChanges();
}
public bool DeleteInventory(Guid Id, string UserId)
{
var inventory = _db.Inventories.Find(Id);
if (inventory == null)
return false;
if (inventory.userId != UserId)
return false;
//Delete items using item service
var items = from i in _db.Items where i.inventoryId.Equals(Id) select i;
foreach(var i in items)
{
_db.Items.Remove(i);
}
_db.Inventories.Remove(inventory);
_db.SaveChanges();
return true;
}
}
}
Service interface it uses:
public interface IInventoryService
{
public List<Inventory> GetInventories(string id);
public void CreateInventory(Inventory newInventory);
public bool DeleteInventory(Guid Id, string UserId);
}
}
Model:
public class Inventory
{
// The Id field is a unique identifier for a specific inventory
[Key]
public Guid Id { get; set; }
// The name of the Inventory. Required to have a value
[Required]
[DisplayName("Inventory Name")]
public string name { get; set; }
public string userId { get; set; }
}
}
Unit test:
public class InventoryTests
{
// Unit test defined for the get user inventories, a valid ID will always be passed in so no need for negative testing
[Fact]
public void Get_user_inventories_with_valid_id()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "Mums 1", userId = u1},
new Inventory { Id = theId1, name = "Mums 1.2", userId = u1},
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
Mock<IInventoryService> myser = new Mock<IInventoryService>();
//ACT
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
var tinvs = myser.Object.GetInventories(u1);
//ASSERT
Assert.Equal(2 , tinvs.Count);
}
//Unit test for creating an inventory, a valid new inventory object will always be passed in so need for negative testing
[Fact]
public void Creating_An_Inventory()
{
//ARRANGE
Guid theId2 = new("00000000-0000-0000-0000-000000000001");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//ACT
Mock<IInventoryService> myser = new Mock<IInventoryService>();
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
Inventory thenew = new Inventory { Id = theId2, name = "Mums 2", userId = u2 };
myser.Object.CreateInventory(thenew);
//ASSERT
Assert.NotNull(data);
}
//Unit test for deleting an inventory. It will always be valid because a guid and user id will be passed in automatically
[Fact]
public void Deleting_An_Inventory()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "123";
//var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "testinv 1", userId = u1},
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//ACT
Mock<IInventoryService> myser = new Mock<IInventoryService>();
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
myser.Object.DeleteInventory(theId1, u1);
var updInvs = myser.Object.GetInventories(u1);
int x = updInvs.Count;
//ASSERT
Assert.Equal(0, x);
}
}
}
I am fairly sure it is a minor error in my setup of the unit test's mocking. any help would be great.
So, if you want to test your InventoryService, you have to mock your dbContext as you do. Better use EF InMemoryDatabase like Microsoft advises https://learn.microsoft.com/en-us/ef/core/testing/#unit-testing
About your tests, I make a few modifications, to test InventoryService. It passes in debug mode.
public class InventoryService : IInventoryService
{
private readonly DBContext _db;
public InventoryService(DBContext db)
{
_db = db;
}
public List<Inventory> GetInventories(string id)
{
//i change inventories to _db.Set<Inventory> which able to be mock
var inventories = (from i in _db.Set<Inventory>() where i.userId.Equals(id) select i).ToList();
return inventories;
}
//ANOTHER CODE
}
[Fact]
public void Get_user_inventories_with_valid_id()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "Mums 1", userId = u1 },
new Inventory { Id = theId1, name = "Mums 1.2", userId = u1 },
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//HERE
var dbMock = new Mock<DBContext>();
dbMock.Setup(x => x.Set<Inventory>()).Returns(mockSet.Object);
var myser = new InventoryService(dbMock.Object);
//ACT
//AND HERE
var tinvs = myser.GetInventories(u1);
//ASSERT
Assert.Equal(2, tinvs.Count);
}
If you want to make InMemory db or test on real SQL db, you look at these questions.
Unit testing EF Core using in-memory database with an eager-loaded function
Unit testing with EF Core and in memory database
I'm new in writing tests and Mock. I'm trying to figure it out how to mock Raw SQL to retrieve data. Here's what I have:
I have DataContext.cs
public class DataContext : DbContext
{
public DataContext()
: base("Main")
{
}
public virtual DbSet<DbBook> Books { get; set; }
public virtual DbSet<DbMovie> Movies { get; set; }
}
I have controller BooksController.cs
public class BooksController : ApiController
{
private readonly BookDataContext _db;
public BooksController ()
{
_db = new BookDataContext();
}
public BooksController (BookDataContext context)
{
_db = context;
}
[HttpGet]
[Route("books")]
public Book GetBooks()
{
using (var dbContextTransaction = _db.Database.BeginTransaction())
{
var test = _db.Books.SqlQuery("select * from BOOK");
var test2 = from b in _db.Books
orderby b.Books
select b;
}
}
}
And I have test
[TestMethod]
public void GetBook()
{
var data = new List<DbBook>
{
new DbBook{ Book = "Book1"},
new DbBook{ Book = "Book2"}
}.AsQueryable();
var mockSet = new Mock<DbSet<DbScriptId>>();
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.GetEnumerator()).Returns(data.GetEnumerator());
mockSet.Setup(m => m.Find(It.IsAny<object[]>()))
.Returns<object[]>(sc => data.SingleOrDefault());
var mockContext = new Mock<DataContext>();
mockContext.Setup(c => c.Books).Returns(mockSet.Object);
var controller = new BooksController (mockContext.Object);
var books = controller.GetBook();
}
I can retrieve data using Linq (test2) but using SqlQuery I always get null (test). How to change that using SqlQuery I get same result as using Linq? Also I'm getting to know that creating InMemory database actually creates some lists (type=IQueriable) in background, not database. Can you please provide some explanation and resolution for this issue?
How about this. (not sure if I understand your question right)
var queryMock = new Mock<DbSqlQuery<DbBook>>();
queryMock.Setup(x => x.GetEnumerator()).Returns(data.GetEnumerator());
mockSet.Setup(m => m.SqlQuery(It.IsAny<string>(), It.IsAny<object[]>())).Returns(queryMock.Object);
This example assumes that all queries will return all items.
Can anyone see where I have went wrong in the following example. I am writing tests to check for an if ID already exists. I have a 'UserService' that calls methods in a generic repository 'RentalsRepository' that makes the calls to the data for me. *Note the code works in the system, just not in my tests
Repo
public class RentalsRepository<T> : IRentalsRepository<T> where T : BaseClass
{
private readonly RentalsDBContext _Context;
private DbSet<T> entities;
string errorMessage = string.Empty;
public RentalsRepository(RentalsDBContext _Context)
{
this._Context = _Context;
entities = _Context.Set<T>();
}
public T Get(string Id)
{
return entities.SingleOrDefault(e => e.Id == Id);
} ...
UserService
public class UserService : IUserService {
private IRentalsRepository<UserAccount> _userRepository;
public UserService(IRentalsRepository<UserAccount> userRepository)
{
this._userRepository = userRepository;
}
public UserAccount GetUserFromId(string id)
{
UserAccount user = _userRepository.Get(id);
user.Email = Encryption.DecryptFromDatabase(user.Email);
return user;
}...
Test Class
[Fact]
public void UserService_GetByID()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring1", Username = "username1"},
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var mockRepo = new Mock<IRentalsRepository<UserAccount>>();
mockRepo.Setup(m => m.Get(It.IsAny<string>())).Returns(mockSet.Object.FirstOrDefault());
var service = new UserService(mockRepo.Object);
UserAccount results = service.GetUserFromId("non-existant");
Assert.Equal("idstring1", results.Id);
}
When I debug I can see the value '"non-existant"' is being used in the method public UserAccount GetUserFromId(string id) but it still somehow returns a user
Latest Attempt
[Fact]
public void UserService_GetUserByUsername()
{
byte[] b = Encryption.GetSalt();
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockContext = new Mock<RentalsDBContext>();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var mockRepo = new Mock<RentalsRepository<UserAccount>>(mockContext.Object);
var testClass = new UserService(mockRepo.Object);
UserAccount results = testClass.GetUserByUsername("username2");
Assert.Equal("username1", results.Username);
}
mockRepo.Setup(m => m.Get(It.IsAny<string>())).Returns(mockSet.Object.FirstOrDefault());
Is going to return the first record in your mock set ("idstring1") no matter what string you pass into Get(). Assuming you get your mocked db context into your repository correctly, there is no reason to mock Get() at all.
Having said that, if you're trying to test if an ID already exists, that's a function of the repository, not your service. All your service is doing is decrypting the email. You're testing both the repository and the service this way, which is not a unit test.
EDIT
We're back to the question of what you are trying to test. If you want to test that the repository retrieves the correct user account, you would mock the db context and use the real repository class.
[Fact]
public void UserRepository_Get()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var testClass = new RentalsRepository<userAccount>(mockContext.Object);
var results = testClass.Get("username2");
Assert.Equal("username2", results.Username);
}
If you want to test that the user service retrieves the user and decrypts the email, you would mock the repository (and it's Get function) and use the real service class.
[Fact]
public void UserService_GetUserByUsername()
{
var userAccount = new UserAccount { Id = "idstring2", Username = "username2", Email = "" };
var mockRepo = new Mock<IRentalsRepository<UserAccount>>();
mockRepo.Setup(m => m.Get("idstring2").Returns(userAccount);
var testClass = new UserService(mockRepo.Object);
var results = testClass.GetUserByUsername("idstring2");
Assert.Equal("idstring2", results.Username);
Assert.AreEqual("???", results.Email);
}
If you want to test both the repository and service together, you certainly can, but it won't be a unit test since you're testing two things at once. In that case, you mock the db context and use real repository and service classes.
[Fact]
public void UserRepository_Get()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var repository = new RentalsRepository<userAccount>(mockContext.Object);
var service = new UserService(repository);
var results = service.GetUserByUsername("username2");
Assert.Equal("username2", results.Username);
}
I'm trying to mock the following method TryGetApns:
private readonly Func<string, ICommunicationClient> _communicationFactory;
public CommunicationApiFacade(Func<string, ICommunicationClient> communicationFactory)
{
_communicationFactory = communicationFactory;
}
public IList<ApnResponse> TryGetApns(string tenant)
{
GetApnsResponse response = null;
try
{
var communicationApiClient = _communicationFactory(tenant);
response = communicationApiClient.JctConfigurationService.GetApns();
}
catch (HttpException e)
{
...
}
return response?.Apns ?? new List<ApnResponse>();
}
with the following test:
private Mock<ICommunicationApiFacade> _communicationApiFacade;
[SetUp]
public void SetUp()
{
_fixture = new Fixture()
.Customize(new AutoMoqCustomization());
_communicationApiFacade = _fixture.Freeze<Mock<ICommunicationApiFacade>>();
}
[Test]
public void RunJctTests_WhenJctIsInAPrivateNetwork_ShouldReturnAPassedTest()
{
// Arrange
var jctApn = _fixture.Create<string>();
var message = _fixture.Build<JctLoggedIn>()
.With(x => x.ApnFromDevice, jctApn)
.Create();
var response = _fixture.Build<ApnResponse>()
.With(x => x.IsPrivateApn, true)
.With(x => x.ApnName, jctApn).Create();
_communicationApiFacade.Setup(x => x.TryGetApns(string.Empty))
.Returns(new List<ApnResponse> { response });
var subject = _fixture.Create<NetworkProviderTestRunner>();
// Act
var result = subject.Execute(message);
// Assert
Assert.That(result.Result, Is.True);
}
and this is the NetworkProviderTestRunner class:
private readonly ICommunicationApiFacade _communicationApi;
public NetworkProviderTestRunner(ICommunicationApiFacade communicationApi)
{
_communicationApi = communicationApi;
}
public JctTest Execute(JctLoggedIn message)
{
var apns = _communicationApi.TryGetApns(message.Tenant);
var jctApn = apns.FirstOrDefault(x => x.ApnName == message.ApnFromDevice);
if (jctApn != null)
{
var privateApn = apns.FirstOrDefault(x => x.PublicApnId.Equals(jctApn.Id));
if (privateApn != null || jctApn.IsPrivateApn)
return new JctTest { Result = true };
}
return new JctTest { Result = false };
}
JctLoggedIn class:
public class JctLoggedIn : Message
{
public string Imei { get; set; }
public string SimCardIdFromDevice { get; set; }
public string SimCardIdFromStorage { get; set; }
public string ApnFromDevice { get; set; }
public string ApnFromStorage { get; set; }
public string FirmwareFromDevice { get; set; }
public int DeviceTypeFromStorage { get; set; }
public int SerialNumber { get; set; }
}
but for some reason I always get back an empty list. I've tried to populate the list in the SetUp and also defining the output there but I's always the same. Any help?
While you could explicitly omit the Tenant property when building the message object, you could also change the Mock setup to this:
_communicationApiFacade.Setup(x => x.TryGetApns(message.Tenant))
.Returns(new List<ApnResponse> { response });
This line
_communicationApiFacade.Setup(x => x.TryGetApns(string.Empty))
.Returns(new List<ApnResponse> { response });
is telling the mock to return the list containing response when TryGetApns is called with an empty string for the tenant parameter.
What is the value of message.Tenant after message is created by this line:
var message = _fixture.Build<JctLoggedIn>()
.With(x => x.ApnFromDevice, jctApn)
.Create();
If it is not string.empty, your mock will not return the reponse list.
Replace
var response = _fixture.Build<ApnResponse>()
.With(x => x.IsPrivateApn, true)
.With(x => x.ApnName, jctApn).Create();
with
var response = _fixture.Build<ApnResponse>()
.With(x => x.Tenant, String.Empty)
.With(x => x.IsPrivateApn, true)
.With(x => x.ApnName, jctApn).Create();
if Tenant is writable.
If the property is writable, AutoFixture will create an object with non-empty value for Tenant without explicitly setting up what you want.
I'm trying to follow this guide for mocking Entity Framework
https://msdn.microsoft.com/en-us/library/dn314429.aspx
The code from the guide works absolutely fine when I build it in my project, but when I'm trying to apply it to my actual context and data objects, I'm getting an exception:
Object reference not set to an instance of an object
My object is pretty simple:
public class NodeAttributeTitle
{
public int ID { get; set; }
[MaxLength(150)]
public string Title { get; set; }
public string Description { get; set; }
}
as is my context
public class DataContext : DbContext
{
public virtual DbSet<NodeAttributeTitle> NodeAttributeTitles { get; set; }
}
and the method I'm trying to set is just a basic insertion
public class CommonNodeAttributes : ICommonNodeAttributes
{
private DataContext _context;
public CommonNodeAttributes(DataContext context)
{
_context = context;
}
public CommonNodeAttributes()
{
_context = new DataContext();
}
public void Insert(string value)
{
var nodeAttributeValue = new NodeAttributeValue();
nodeAttributeValue.Value = value;
nodeAttributeValue.Parent = 0;
_context.NodeAttributeValues.Add(nodeAttributeValue);
_context.SaveChanges();
}
}
And the test class is following the same syntax as in the MSDN guide
[TestClass]
public class CommonNodeAttributesTests
{
[TestMethod]
public void CreateNodeAttribute_saves_a_nodeattribute_via_context()
{
var mockSet = new Mock<DbSet<NodeAttributeTitle>>();
var mockContext = new Mock<DataContext>();
mockContext.Setup(m => m.NodeAttributeTitles).Returns(mockSet.Object);
var service = new CommonNodeAttributes(mockContext.Object);
service.Insert("blarg");
mockSet.Verify(m => m.Add(It.IsAny<NodeAttributeTitle>()),Times.Once());
mockContext.Verify(m => m.SaveChanges(),Times.Once);
}
}
and yet when the test runs, I get
Tests.CommonNodeAttributesTests.CreateNodeAttribute_saves_a_nodeattribute_via_context threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
I don't understand why the code in the guide works fine, but my code doesn't.
I've tried adding 'virtual' to the ID, Title and Description properties but that doesn't do anything either. Does anyone have any clue what might be different for me?
You need to give some data in your mock:
IQueryable<NodeAttributeTitle> data = new List<NodeAttributeTitle>
{
new NodeAttributeTitle() {Id = 1, Title = "t1"},
new NodeAttributeTitle() {Id = 2, Title = "t2"},
}.AsQueryable();
var mockSet = new Mock<IDbSet<NodeAttributeTitle>>();
mockSet .Setup(m => m.Provider).Returns(data.Provider);
mockSet .Setup(m => m.Expression).Returns(data.Expression);
mockSet .Setup(m => m.ElementType).Returns(data.ElementType);
mockSet .Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
Then you can pass it to your DbContext:
Your problem in code is in the Add method ( _context.NodeAttributeValues.Add(nodeAttributeValue);) is not mocked!