JustMock Entity Framework Update Record - c#

I've read through the examples on JustMock (we have the paid version FYI) but am having difficulty in regards to updating a record (not adding).
I have a ILogRepo of
public interface ILogRepo
{
DbSet<LogEntry> LogEntries { get; }
LogContext LogContext { get; }
}
I have a LogInteraction of
public class LogInteraction : ILogInteraction
{
private readonly ILogRepo _logRepo;
public LogInteraction(ILogRepo logRepo)
{
_logRepo = logRepo;
}
public void UpdateLog(IList<AckDetail> ackDetails)
{
foreach (var ackDetail in ackDetails)
{
var logRecord = _logRepo.LogEntries.Single(r => r.CheckNum == ackDetail.CheckNo);
logRecord.ProcessingStatus = ackDetail.Result.ToString();
if (!string.IsNullOrWhiteSpace(ackDetail.Message))
{
logRecord.Message = ackDetail.Message;
}
}
_logRepo.LogContext.SaveChanges();
}
}
I've mocked out a fake LogEntries (it's an IList). And last but not least a test of
[TestFixture]
public class LogTests
{
private ILogRepo _mockLogRepo;
private ILogInteraction _uut;
private IList<AckDetail> _fakeAckDetails;
[SetUp]
public void SetUp()
{
//Arrange
_mockLogRepo = Mock.Create<ILogRepo>();
_fakeAckDetails = FakeAckDetails();
_uut = new LogInteraction(_mockLogRepo);
}
[Test]
public void LogUpdated()
{
//Arrange
var expectedResults = FakeLogEntries_AfterAckProcessing();
var expectedJson = JsonConvert.SerializeObject(expectedResults);
_mockLogRepo.Arrange(m => m.LogEntries).IgnoreInstance().ReturnsCollection(FakeLogEntries_AfterSending());
//Act
_uut.UpdateLog(_fakeAckDetails);
var actualResults = _mockLogRepo.LogEntries.ToList();
var actualJson = JsonConvert.SerializeObject(actualResults);
//Assert
Assert.AreEqual(expectedResults.Count, actualResults.Count);
Assert.AreEqual(expectedJson, actualJson);
}
}
In my test, my _mockLogRepo is not being updated by my LogInteraction. Stepping through the code everything seems all well and good. If I inspect the context though and look for changes, that returns a false though. I think I've matched the example on Telerik's site pretty well, but I've only been able to find info on Adding (and by extrapolating, Removing). But since those two are actual methods and Updating isn't in Entity Framework I'm at a bit of a loss. My code will work in production, but I'd like it to work in Test too (kind of the whole point).

Related

Record odd behavior in Unit Tests

I've written unit tests using NSubstitute library and faced with odd Records behavior.
Assuming I have the code:
public record SomeModel
{
//fields
}
public interface ISomeService
{
public string DoSmth(SomeModel model);
}
public class SomeClass
{
private ISomeService _service;
public SomeClass(ISomeService service)
{
_service = service;
}
public string MethodToTest(SomeModel model)
{
return _service.DoSmth(model);
}
}
And I want to cover it with the Unit test:
[Fact]
public void Test()
{
var model = Substitute.For<SomeModel>();
var service = Substitute.For<ISomeService>();
service.DoSmth(model).Returns("1234");
var sut = new SomeClass(service);
var value = sut.MethodToTest(model); //it returns Empty sting here
value.Should().Be("1234");
}
But it Fails, because MethodToTest returns Empty string.
If I change SomeModel from record to class it is working fine.
Could someone point me to what I missed here?
Update: I changed the model initialization in my test method:
[Fact]
public void Test()
{
var model = new SomeModel();
//other code
}
In this case, it is working. But I still don't understand why it isn't working in the initial example?
Update 2. It is even working if I use Substitute.ForPartsOf:
[Fact]
public void Test()
{
var model = Substitute.ForPartsOf<SomeModel>();
//other code
}

Unit Testing a Class With A Private Constructor

I am trying to test a class that only has a private constructor. This is for a course registration system. The courses do not get create via our application, therefore we intentionally have no public constructor. Instead we use EF to get the courses that are already in the database, and register students to them.
I am trying to test the register method of the Course class, however I have no way of creating an instance. I could use
course = (Course)Activator.CreateInstance(typeof(Course), true);, but then I don't have a way to setup the necessary properties since those are private.
What is the recommended approach for unit testing without a constructor?
This is a slimmed down version of the code.
public class Course
{
private Course()
{
}
public int Id { get; private set; }
public string Name { get; private set; }
public bool Open { get; private set; }
public virtual ICollection<Student> Students { get; private set; }
public void Register(string studentName)
{
if (Open)
{
var student = new Student(studentName);
Students.Add(student);
}
}
}
// Usage //
using (var db = new SchoolContext())
{
var course = db.Courses.Include(x => x.Students).Where(x => x.Name == courseName).First();
course.Register(studentName);
db.SaveChanges();
}
// Unit Test //
[Fact]
public void CanRegisterStudentForOpenClass(){
// HERE I HAVE NO WAY TO CHANGE THE OPEN VARIABLE
var course = (Course)Activator.CreateInstance(typeof(Course), true);
course.Register("Bob");
}
Yes you can using reflexion. your code is neraly there;
you can get properties and fields of the types with typeof(Course).GetProperty("PropertyName") then you can use SetValue to set the desired value, and pass as parameter first the instance to modify then the value.
in your case true;
note: in your example you will need to add the Collection of students too, if your Open is true.
Here there is a working example:
[Fact]
public void CanRegisterStudentForOpenClass()
{
var course = (Course)Activator.CreateInstance(typeof(Course), true);
typeof(Course).GetProperty("Open").SetValue(course, true, null);
ICollection<Student> students = new List<Student>();
typeof(Course).GetProperty("Students").SetValue(course, students, null);
course.Register("Bob");
Assert.Single(course.Students);
}
If you would rather not use reflection, then I recommend you use internal classes (instead of private) and using the InternalsVisibleToAttribute on your implementation assembly.
You can find more about the attribute here. Here's a quick guide on how you can use it!
Step 1. Add this attribute to your assembly that wants its internal code tested.
[assembly: InternalsVisibleToAttribute("MyUnitTestedProject.UnitTests")]
Step 2. Change private to internal.
public class Course
{
internal Course()
{
}
public int Id { get; internal set; }
public string Name { get; internal set; }
public bool Open { get; internal set; }
public virtual ICollection<Student> Students { get; internal set; }
/* ... */
}
Step 3. Write your tests like normal!
[Fact]
public void CanRegisterStudentForOpenClass()
{
var course = new Course();
course.Id = "#####";
course.Register("Bob");
}
As a few people have mentioned here, unit testing something private is either a code smell, or a sign you're writing the wrong tests.
In this case, what you would want to do is use EF's in-memory database if you're using Core, or mocking with EF6.
For EF6 You can follow the docs here
I would say rather than newing your dbContext where you do, pass it in via Dependency Injection. If that's beyond the scope of the work you're doing, (I'm assuming this is actual coursework, so going to DI may be overkill) then you can create a wrapper class that takes a dbcontext and use that in place.
Taking a few liberties with where this code is called from...
class Semester
{
//...skipping members etc
//if your original is like this
public RegisterCourses(Student student)
{
using (var db = new SchoolContext())
{
RegisterCourses(student, db);
}
}
//change it to this
public RegisterCourses(Student student, SchoolContext db)
{
var course = db.Courses.Include(x => x.Students).Where(x => x.Name == courseName).First();
course.Register(studentName);
db.SaveChanges();
}
}
[Fact]
public void CanRegisterStudentForOpenClass()
{
//following after https://learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking#testing-query-scenarios
var mockCourseSet = new Mock<DbSet<Course>>();
mockCourseSet.As<IQueryable<Course>>().Setup(m => m.Provider).Returns(data.Provider);
mockCourseSet.As<IQueryable<Course>>().Setup(m => m.Expression).Returns(data.Expression);
mockCourseSet.As<IQueryable<Course>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockCourseSet.As<IQueryable<Course>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//create an aditional mock for the Student dbset
mockStudentSet.As.........
var mockContext = new Mock<SchoolContext>();
mockContext.Setup(c => c.Courses).Returns(mockCourseSet.Object);
//same for student so we can include it
mockContext.Include(It.IsAny<string>()).Returns(mockStudentSet); //you can change the isAny here to check for Bob or such
var student = Institution.GetStudent("Bob");
var semester = Institution.GetSemester(Semester.One);
semester.RegisterCourses(student, mockContext);
}
If you're using EFCore you can follow it along from here
You can fake private constructors and members using TypeMock Isolator or JustMock (both paid) or using MS Fakes (only available in VS Enterprise).
There is also a free Pose library that allows you to fake access to properties.
Unfortunately, the private constructor can't be forged. Therefore, you will need to create an instance of the class using reflection.
Add package.
Open namespace:
using Pose;
Test code:
[Fact]
public void CanRegisterStudentForOpenClass()
{
var course = (Course)Activator.CreateInstance(typeof(Course), true);
ICollection<Student> students = new List<Student>();
Shim studentsPropShim = Shim.Replace(() => Is.A<Course>().Students)
.With((Course _) => students);
Shim openPropShim = Shim.Replace(() => Is.A<Course>().Open)
.With((Course _) => true);
int actual = 0;
PoseContext.Isolate(() =>
{
course.Register("Bob");
actual = course.Students.Count;
},
studentsPropShim, openPropShim);
Assert.Equal(1, actual);
}
You can create a JSON representation of your default instance and deserialize it with Newtonsoft.
Something like this:
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using privateConstructor;
namespace privateConstructorTest
{
[TestClass]
public class CourseTest
{
[TestMethod]
public void Register_WhenOpenIsTrue_EnableAddStudents()
{
// Arrange
const string json = #"{'Id': 1, 'name':'My Course', 'open':'true', 'students':[]}";
var course = CreateInstance<Course>(json);
// Act
course.Register("Bob");
// Assert
Assert.AreEqual(1, course.Students.Count);
}
[TestMethod]
public void Register_WhenOpenIsFalse_DisableAddStudents()
{
// Arrange
const string json = #"{'Id': 1, 'name':'My Course', 'open':'false', 'students':[]}";
var course = CreateInstance<Course>(json);
// Act
course.Register("Bob");
// Assert
Assert.AreEqual(0, course.Students.Count);
}
private static T CreateInstance<T>(string json) =>
JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
ContractResolver = new ContractResolverWithPrivates()
});
public class ContractResolverWithPrivates : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var prop = base.CreateProperty(member, memberSerialization);
if (prop.Writable) return prop;
var property = member as PropertyInfo;
if (property == null) return prop;
var hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
return prop;
}
}
}
}
In order to have a cleaner test class, you can extract the JSON strings and the helper code that creates the instance.

Testing async method does not give consistent result

I am trying to figure out the reason why my unit test would fail when run together with other unit tests in the solution but pass when run alone. Can anyone show me what am I missing?
The SUT is a class called CompositeClient that is essentially a wrapper class around two other clients. It's main idea is to give priority to one of those clients to be called.
public class CompositeClient : IReceiverChannel
{
private static readonly List<IReceiverChannel> ReceiverChannels = new List<IReceiverChannel>();
public CompositeClient(IReceiverChannel priority, IReceiverChannel normal)
{
ReceiverChannels.Add(priority);
ReceiverChannels.Add(normal);
}
public async Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
var req = new List<Request>();
foreach (var channel in ReceiverChannels)
{
req.AddRange(await channel.ReceiveBatchAsync(batchSize - req.Count).ConfigureAwait(false));
if (req.Count >= batchSize)
{
break;
}
}
return req;
}
}
Running the unit test below with all the other unit tests in the solution yield me a failed result. But if I run this test alone, it will pass.
[TestMethod]
public async Task ReceivedRequestShouldComeFromPriorityClientFirst()
{
var normalPriorityClient = GetNormalClientMock();
var highPriorityClient = GetPriorityClientMock();
var compositeClient = new CompositeClient(highPriorityClient, normalPriorityClient);
var requests = await compositeClient.ReceiveBatchAsync(1);
requests.Should().HaveCount(1);
requests.First().Origin.Should().BeSameAs("priority");
normalPriorityClient.CallCount.Should().Be(1); // It will fail here with actual CallCount = 0.
highPriorityClient.CallCount.Should().Be(0);
}
private static ReceiverChannelMock GetNormalClientMock()
{
return new ReceiverChannelMock("normal");
}
private static ReceiverChannelMock GetPriorityClientMock()
{
return new ReceiverChannelMock("priority");
}
private class ReceiverChannelMock : IReceiverChannel
{
private readonly string name;
public ReceiverChannelMock(string name)
{
this.name = name;
}
public int CallCount { get; private set; }
public Task<IEnumerable<Request>> ReceiveBatchAsync(int batchSize)
{
this.CallCount++;
return Task.FromResult<IEnumerable<Request>>(
new List<Request>
{
new Request
{
Origin = this.name
}
});
}
}
Tools used:
Visual Studio 2013
.NET Framework 4.5.2
Resharper 9.2
FluentAssertion
As David pointed out, I overlooked the static field that I declared in the CompositeClient class. Removing the static keyword solved the issue.

Creating a hybrid of a mock and an anonymous object using e.g. Moq and AutoFixture?

I encountered a class during my work that looks like this:
public class MyObject
{
public int? A {get; set;}
public int? B {get; set;}
public int? C {get; set;}
public virtual int? GetSomeValue()
{
//simplified behavior:
return A ?? B ?? C;
}
}
The issue is that I have some code that accesses A, B and C and calls the GetSomeValue() method (now, I'd say this is not a good design, but sometimes my hands are tied ;-)). I want to create a mock of this object, which, at the same time, has A, B and C set to some values. So, when I use moq as such:
var m = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };
lets me setup a result on GetSomeValue() method, but all the properties are set to null (and setting up all of them using Setup() is quite cumbersome, since the real object is a nasty data object and has more properties than in above simplified example).
So on the other hand, using AutoFixture like this:
var fixture = new Fixture();
var anyMyObject = fixture.CreateAnonymous<MyObject>();
Leaves me without the ability to stup a call to GetSomeValue() method.
Is there any way to combine the two, to have anonymous values and the ability to setup call results?
Edit
Based on nemesv's answer, I derived the following utility method (hope I got it right):
public static Mock<T> AnonymousMock<T>() where T : class
{
var mock = new Mock<T>();
fixture.Customize<T>(c => c.FromFactory(() => mock.Object));
fixture.CreateAnonymous<T>();
fixture.Customizations.RemoveAt(0);
return mock;
}
This is actually possible to do with AutoFixture, but it does require a bit of tweaking. The extensibility points are all there, but I admit that in this case, the solution isn't particularly discoverable.
It becomes even harder if you want it to work with nested/complex types.
Given the MyObject class above, as well as this MyParent class:
public class MyParent
{
public MyObject Object { get; set; }
public string Text { get; set; }
}
these unit tests all pass:
public class Scenario
{
[Fact]
public void CreateMyObject()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyObject>();
Assert.NotNull(actual.A);
Assert.NotNull(actual.B);
Assert.NotNull(actual.C);
}
[Fact]
public void MyObjectIsMock()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyObject>();
Assert.NotNull(Mock.Get(actual));
}
[Fact]
public void CreateMyParent()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyParent>();
Assert.NotNull(actual.Object);
Assert.NotNull(actual.Text);
Assert.NotNull(Mock.Get(actual.Object));
}
[Fact]
public void MyParentIsMock()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyParent>();
Assert.NotNull(Mock.Get(actual));
}
}
What's in MockHybridCustomization? This:
public class MockHybridCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new MockPostprocessor(
new MethodInvoker(
new MockConstructorQuery())));
fixture.Customizations.Add(
new Postprocessor(
new MockRelay(t =>
t == typeof(MyObject) || t == typeof(MyParent)),
new AutoExceptMoqPropertiesCommand().Execute,
new AnyTypeSpecification()));
}
}
The MockPostprocessor, MockConstructorQuery and MockRelay classes are defined in the AutoMoq extension to AutoFixture, so you'll need to add a reference to this library. However, note that it's not required to add the AutoMoqCustomization.
The AutoExceptMoqPropertiesCommand class is also custom-built for the occasion:
public class AutoExceptMoqPropertiesCommand : AutoPropertiesCommand<object>
{
public AutoExceptMoqPropertiesCommand()
: base(new NoInterceptorsSpecification())
{
}
protected override Type GetSpecimenType(object specimen)
{
return specimen.GetType();
}
private class NoInterceptorsSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var fi = request as FieldInfo;
if (fi != null)
{
if (fi.Name == "__interceptors")
return false;
}
return true;
}
}
}
This solution provides a general solution to the question. However, it hasn't been extensively tested, so I'd love to get feedback on it.
Probably there is a better why, but this works:
var fixture = new Fixture();
var moq = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };
moq.Setup(m => m.GetSomeValue()).Returns(3);
fixture.Customize<MyObject>(c => c.FromFactory(() => moq.Object));
var anyMyObject = fixture.CreateAnonymous<MyObject>();
Assert.AreEqual(3, anyMyObject.GetSomeValue());
Assert.IsNotNull(anyMyObject.A);
//...
Initially I tried to use fixture.Register(() => moq.Object); instead of fixture.Customize but it registers the creator function with OmitAutoProperties() so it wouldn't work for you case.
As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
var mock = fixture.Create<Mock<MyObject>>();
Assert.NotNull(mock.Object.A);
Assert.NotNull(mock.Object.B);
Assert.NotNull(mock.Object.C);

RhinoMocks: how to test if method was called when using PartialMock

I have a clas that is something like this
public class MyClass
{
public virtual string MethodA(Command cmd)
{ //some code here}
public void MethodB(SomeType obj)
{
// do some work
MethodA(command);
}
}
I mocked MyClass as PartialMock (mocks.PartialMock<MyClass>) and I setup expectation for MethodA
var cmd = new Command();
//set the cmd to expected state
Expect.Call(MyClass.MethodA(cmd)).Repeat.Once();
Problem is that MethodB calls actual implementation of MethodA instead of mocking it up. I must be doing something wrong (not very experienced with RhinoMocks). How do I force it to mock MetdhodA?
Here is the actual code:
var cmd = new SetBaseProductCoInsuranceCommand();
cmd.BaseProduct = planBaseProduct;
var insuredType = mocks.DynamicMock<InsuredType>();
Expect.Call(insuredType.Code).Return(InsuredTypeCode.AllInsureds);
cmd.Values.Add(new SetBaseProductCoInsuranceCommand.CoInsuranceValues()
{
CoInsurancePercent = 0,
InsuredType = insuredType,
PolicySupplierType = ppProvider
});
Expect.Call(() => service.SetCoInsurancePercentages(cmd)).Repeat.Once();
mocks.ReplayAll();
//act
service.DefaultCoInsurancesFor(planBaseProduct);
//assert
service.AssertWasCalled(x => x.SetCoInsurancePercentages(cmd),x=>x.Repeat.Once());
I've tried to reproduce this issue, and it seems to work fine, what is different between my test code (below) and yours?
public class MyClass
{
public virtual string MethodA(object cmd)
{
return "implementation";
}
public string MethodB(object obj)
{
// do some work
return MethodA(obj);
}
}
[TestFixture]
public class MyClassTests
{
[Test]
public void MockTest()
{
var myClassMock = MockRepository.GenerateMock<MyClass>();
myClassMock.Expect(x => x.MethodA("x")).Return("mock");
Assert.AreEqual("mock", myClassMock.MethodB("x"));
myClassMock.VerifyAllExpectations();
}
}
The issue here seems to be that while in your comments you said PartialMock, but in your code sample you use DynamicMock. I believe this is the source of your issues, as they behave differently.

Categories

Resources