Global equivalency config. Excluding members - c#

I'm wondering if I can do a global config for a test. I know that I can compare this object something like that:
x.Should().BeEquivalentTo(y, opt => opt.Excluding(z => z.Member)
But I want all the methods in my test to use this config.

To exclude a member from a specific type, you can create a custom IMemberSelectionRule.
To use that selection rule for all tests, use the static AssertionOptions.AssertEquivalencyUsing in some setup method of your unit testing framework.
Be aware that AssertionOptions.AssertEquivalencyUsing changes static state of Fluent Assertions, so if you're running tests in parallel it should be invoked before any tests are run.
For NUnit that would be [OneTimeSetUp] inside a [SetUpFixture] not inside a namespace.
using FluentAssertions;
using FluentAssertions.Equivalency;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
[SetUpFixture]
public class MySetUpClass
{
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
AssertionOptions.AssertEquivalencyUsing(e => e.Using(new MyNamespace.MyClassSelectionRule()));
}
}
namespace MyNamespace
{
class MyOuterClass
{
public MyInnerClass MemberToInclude { get; set; }
public int MemberToExclude { get; set; }
}
class MyInnerClass
{
public int AnotherMemberToInclude { get; set; }
public int MemberToExclude { get; set; }
}
internal class MyClassSelectionRule : IMemberSelectionRule
{
public bool IncludesMembers => false;
public IEnumerable<SelectedMemberInfo> SelectMembers(IEnumerable<SelectedMemberInfo> selectedMembers, IMemberInfo context, IEquivalencyAssertionOptions config) =>
selectedMembers.Where(e => !(e.DeclaringType.Name == nameof(MyOuterClass) && e.Name == nameof(MyOuterClass.MemberToExclude)));
}
[TestFixture]
public class UnitTest1
{
[Test]
public void Ignore_the_member_MemberToExclude_on_MyOuterClass()
{
var subject = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
AnotherMemberToInclude = 42,
MemberToExclude = 42
},
MemberToExclude = 1
};
var expectation = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
AnotherMemberToInclude = 42,
MemberToExclude = 42
},
MemberToExclude = 2
};
subject.Should().BeEquivalentTo(expectation);
}
[Test]
public void Do_not_ignore_the_member_MemberToExclude_on_MyInnerClass()
{
var subject = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
MemberToExclude = 1
},
};
var expectation = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
MemberToExclude = 2
},
};
Action act = () => subject.Should().BeEquivalentTo(expectation);
act.Should().Throw<AssertionException>();
}
}
}

Related

Handle Generic Property between 2 Maps and avoid repeat code

I wanted to ask about a scenario that happened to me.
I am working with different models that implement a common generic property, which has different implementations, however, this generic property is common.
In this case, I am doing a Mapping where they have a generic property T in common with other models, in the example I created it is Comparable and NonComparable, both implement a Unit T.
Initially, I have a Mapper for comparable and another for IComparable, as you can see:
Code Link: https://github.com/xeof-landmark/generic-tests
Branch: main
Repeating Code Here:
Program
class Program
{
static Fixture fixture = new Fixture();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var map = new Map();
var unitsComparables = InitializeComparables();
var unitsNonComparables = InitializeNonComparables();
var unitsMappedCompared = map.MapList(unitsComparables);
var unitsMappedNonCompared = map.MapList(unitsNonComparables);
var units = new List<IUnit>();
units.AddRange(unitsMappedCompared);
units.AddRange(unitsMappedNonCompared);
foreach (var unit in units)
{
Console.WriteLine(unit.Name);
Console.WriteLine(Environment.NewLine);
}
}
static List<Comparable<IUnit>> InitializeComparables()
{
return new List<Comparable<IUnit>>()
{
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
static List<NonComparable<IUnit>> InitializeNonComparables()
{
return new List<NonComparable<IUnit>>()
{
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
}
Classes:
public class SaleUnit : IUnit
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class LegacyUnit : IUnit
{
public int Id { get; set; }
private string name;
public string Name
{
get { return $"{name}.Legacy"; }
set { name = value; }
}
public string Description { get; set; }
}
public interface IUnit
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Comparable<T>
where T : IUnit
{
public T Unit { get; set; }
public int ExisingUnit { get; set; }
}
public class NonComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public bool IsDifferent(int id) => true;
public void AddNewPrices(decimal prices) => throw new System.NotImplementedException();
}
Mapper
public class Map
{
static Fixture fixture = new Fixture();
public List<IUnit> MapList(List<Comparable<IUnit>> compareOnes)
{
return new List<IUnit>()
{
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<SaleUnit>(),
fixture.Create<SaleUnit>(),
};
}
public List<IUnit> MapList(List<NonComparable<IUnit>> compareOnes)
{
return new List<IUnit>()
{
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<SaleUnit>(),
fixture.Create<SaleUnit>(),
};
}
}
I realized that at first, I was repeating a lot of code, in turn, I was reading a bit about covariance (I tried to do it but I couldn't).
I ended up solving it by casting them as an IComparable interface and then using a common Mapper for the IComparables.
Resolution Link: https://github.com/xeof-landmark/generic-tests/pull/1
So I ended up doing this
First I've created a new Interface to abstract the generic Unit.
public interface IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
}
I have inherited the Comparable and NonComparable from IComparable
public class Comparable<T> : IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public int ExisingUnit { get; set; }
}
public class NonComparable<T> : IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public bool IsDifferent(int id) => true;
public void AddNewPrices(decimal prices) => throw new System.NotImplementedException();
}
Then I added a new method overload to my Map Class to handle both Comparable and NonComparable MapList(List<IComparable> unitsComparables) to be able to handle both maps.
public List<IUnit> MapList(List<IComparable<IUnit>> unitsComparables)
{
var mapUnitComparables = unitsComparables.Where(x => x is Comparable<IUnit>).Select(s => (Comparable<IUnit>)s).ToList();
var mapUnitNonComparables = unitsComparables.Where(x => x is NonComparable<IUnit>).Select(s => (NonComparable<IUnit>)s).ToList();
var result = new List<IUnit>();
result.AddRange(MapList(mapUnitComparables));
result.AddRange(MapList(mapUnitNonComparables));
return result;
}
And Finally my Program:
class Program
{
static Fixture fixture = new Fixture();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var map = new Map();
var unitsComparables = InitializeComparables();
var units = map.MapList(unitsComparables);
foreach (var unit in units)
{
Console.WriteLine(unit.Name);
Console.WriteLine(Environment.NewLine);
}
}
static List<IComparable<IUnit>> InitializeComparables()
{
return new List<IComparable<IUnit>>()
{
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
}
Now my question is, this solves it, but .....
Would it be the best way to solve it? or can it be done better?
Could I use covariance on this occasion? is it well planned?

Why can't I get Automapper Parameterization to work

Given the following Automapper profile :
public class MyProfile: Profile
{
private int? _injectedInt;
public MyProfile()
{
CreateMap<objectA, objectB>()
.ForMember(e => e.myNullableInt, x => x.MapFrom(s =>_injectedInt.HasValue ? 100 : 0));
}
}
And the following code :
var result = queryableOfObjectA.ProjectTo<objectB>(new { _injectedInt = 1 });
var resultingValue = result.FirstOrDefault().myNullableInt;
Why is "resultingValue" returning 0 instead of 100?
I can't see what I have done wrong from the docs:
http://docs.automapper.org/en/stable/Queryable-Extensions.html#parameterization
I think the place where _injectedInt is declared might be the issue. I have written following test and 100 is returned.
[TestClass]
public class UnitTest19
{
[TestMethod]
public void TestMethod1()
{
Mapper.Initialize(expression => expression.AddProfile(new MyProfile()));
var queryableOfObjectA = new List<objectA>
{
new objectA
{
myNullableInt = 10
}
};
var result = queryableOfObjectA.AsQueryable().ProjectTo<objectB>(new { _injectedInt = (int?)1 });
var resultingValue = result.FirstOrDefault()?.myNullableInt;
Assert.AreEqual(100, resultingValue);
}
}
public class MyProfile : Profile
{
public MyProfile()
{
int? _injectedInt = null;
CreateMap<objectA, objectB>()
.ForMember(e => e.myNullableInt, x => x.MapFrom(s => _injectedInt.HasValue ? 100 : 0));
}
}
public class objectA
{
public int myNullableInt { get; set; }
}
public class objectB
{
public int myNullableInt { get; set; }
}

Assert.True Not Passing Tests

I am using NUnit Testing Framework for the first time and whenever I Run Tests for my code it only passes Assert.False commands, while failing every Assert.True I use. When i run the test below, only TestNotAreYou() is the only one that passes. Is my code wrong or do I have a technical problem?
Code:
using System;
using NUnit.Framework;
using System.Collections.Generic;
namespace Week22
{
[TestFixture]
public class Test
{
private IdentifiableObject id;
[SetUp]
public void SetUp()
{
id = new IdentifiableObject(new string[] { "fred", "bob" });
}
[Test]
public void TestAreYou()
{
IdentifiableObject id = new IdentifiableObject(new string[] { "fred", "bob" });
Assert.True(id.AreYou("fred"));
Assert.True(id.AreYou("bob"));
}
[Test]
public void TestNotAreYou()
{
IdentifiableObject id = new IdentifiableObject(new string[] { "fred", "bob" });
Assert.False(id.AreYou("wilma"));
Assert.False(id.AreYou("boby"));
}
[Test]
public void TestCaseSens()
{
IdentifiableObject id = new IdentifiableObject(new string[] { "fred", "bob" });
Assert.True(id.AreYou("fred"));
Assert.True(id.AreYou("bob"));
Assert.True(id.AreYou("Fred"));
Assert.True(id.AreYou("bOB"));
}
[Test]
public void TestFirstID()
{
IdentifiableObject id = new IdentifiableObject(new string[] { "fred", "bob" });
Assert.True(id.FirstID == "fred");
}
[Test]
public void TestAddID()
{
IdentifiableObject id = new IdentifiableObject(new string[] { "fred", "bob" });
id.AddIdentifier("wilma");
Assert.True(id.AreYou("fred"));
Assert.True(id.AreYou("bob"));
Assert.True(id.AreYou("wilma"));
}
}
}
Program thats being tested:
using System.Linq;
using System;
using System.Collections.Generic;
using System.Text;
namespace Week22
{
public class IdentifiableObject
{
private List<string> _identifiers = new List<string>();
public IdentifiableObject(string[] idents)
{
Array.ForEach(idents, s => AddIdentifier("true"));
}
public bool AreYou(string id)
{
return _identifiers.Contains(id.ToLower());
}
public string FirstID
{
get
{
return _identifiers.First();
}
}
public void AddIdentifier(string id)
{
_identifiers.Add(id.ToLower());
}
}
}
This has nothing to do with unit tests. In your code, you're iterating over the identifiers:
Array.ForEach(idents, s => AddIdentifier("true"));
You're adding the string "true" for each identifier. Instead add s.
You can debug unit tests. Then set a breakpoint and step through your code to inspect your variables.
your method public void AddIdentifier(string id) I believe is only ever adding "true" maybe try replacing
public IdentifiableObject(string[] idents)
{
Array.ForEach(idents, s => AddIdentifier("true"));
}
with
public IdentifiableObject(string[] idents)
{
Array.ForEach(idents, s => AddIdentifier(s));
}
I guess you should pass s to the function, not "true".
here: Array.ForEach(idents, s => AddIdentifier("true"));
should be: Array.ForEach(idents, s => AddIdentifier(s));

NHibernate Unit test fails with Null Reference Exception

My test is setup with mocking data like this
var persons = new List<Core.Domain.Person>
{
new Core.Domain.Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = "coord001" },
new Core.Domain.Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = "coord002" }
};
this.mockUnitOfWork.Setup(x => x.Query<Core.Domain.Person>()).Returns(persons.AsQueryable);
In the code to test the persons are retrieved like this
private Dictionary<string, Domain.Person> GetPersons(IEnumerable<string> wurAccounts)
{
var accounts = wurAccounts.ToList();
return this.session.Query<Domain.Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
When I run the test I get a NullReferenceException here:
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
at Wur.P2G.Core.Services.PersonSynchronizer.GetPersons(IEnumerable`1 wurAccounts) in C:\Projects\P2G\P2G\Sources\Wur.P2G.Core\Services\PersonSynchronizer.cs:line 112
EDIT
I was able to boile it down to this piece of code that still causes the NullReference Exception:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using NHibernate;
using NHibernate.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Wur.P2G.Core.Services.Tests
{
public interface IUnitOfWork : IDisposable
{
ISession Session { get; }
IQueryable<T> Query<T>();
void BeginTransaction();
void Commit();
void Rollback();
}
public class Person
{
public virtual string WurAccount { get; set; }
public virtual string DisplayName { get; set; }
public virtual string Email { get; set; }
public virtual bool HasValidEmail => true;
public override string ToString() => WurAccount;
}
[TestClass()]
public class PersonSynchronizerTests
{
private Mock<IUnitOfWork> mockUnitOfWork;
private Mock<ISession> mockSession;
[TestInitialize]
public void Initialize()
{
this.mockUnitOfWork = new Mock<IUnitOfWork>();
this.mockSession = new Mock<ISession>();
this.mockUnitOfWork.Setup(x => x.Session).Returns(this.mockSession.Object);
}
[TestMethod()]
public void GetPersonsTest()
{
var persons = new List<Person>
{
new Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = "coord001" },
new Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = "coord002" }
};
this.mockUnitOfWork.Setup(x => x.Query<Person>()).Returns(persons.AsQueryable);
var wurAccounts = new[] { "coord001", "coord002" };
var accounts = wurAccounts.ToList();
var personsRead = mockSession.Object.Query<Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
}
}
Some more text because the stupid editor want it from me.
While the error message shows that the problem is related to NHibernate.Linq, None of the code shown so far is related to NHibernate unless there is something you are not showing that is using it.
The code shown so far should work as expected as demonstrated by the following minimal, complete and verifiable example based on the original example provided.
[TestClass]
public class PersonSynchronizerTest {
[TestMethod]
public void PersonSynchronizer_GetPerson_Should_Return_Two() {
//Arrange
var wurAccounts = new[] { "coord001", "coord002" };
var persons = new List<Person> {
new Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = wurAccounts[0] },
new Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = wurAccounts[1] }
};
var mockSession = new Mock<ISession>();
mockSession.Setup(_ => _.Query<Person>()).Returns(persons.AsQueryable); //<-- setup session
var mockUnitOfWork = new Mock<IUnitOfWork>();
mockUnitOfWork.Setup(_ => _.Query<Person>()).Returns(persons.AsQueryable);
mockUnitOfWork.Setup(_ => _.Session).Returns(mockSession.Object); //<-- UoW returns session
var subject = new PersonSynchronizer(mockUnitOfWork.Object);
//Act
var actual = subject.GetPersons(wurAccounts);
//Assert
actual.Should()
.NotBeNull()
.And.HaveCount(wurAccounts.Length);
}
public class PersonSynchronizer {
private IUnitOfWork unitOfWork;
private ISession session;
public PersonSynchronizer(IUnitOfWork uow) {
this.unitOfWork = uow;
this.session = unitOfWork.Session;
}
public Dictionary<string, Person> GetPersons(IEnumerable<string> wurAccounts) {
var accounts = wurAccounts.ToList();
return this.session.Query<Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
}
public class Person {
public string DisplayName { get; set; }
public string Email { get; set; }
public string WurAccount { get; set; }
}
public interface IUnitOfWork : IDisposable {
ISession Session { get; }
IQueryable<T> Query<T>();
void BeginTransaction();
void Commit();
void Rollback();
}
public interface ISession {
IQueryable<T> Query<T>();
}
}
The snippet above passes as expected when tested.
I suggest reviewing if there are any NHibernate extension methods being called that may be conflicting with the default Linq Extensions, causing the issues encountered.

How to invoke Action set in property of Moq input parameter

I have the following method in a ViewModel.
public void ViewModelMethod()
{
UserDialogs.Confirm(new ConfirmConfig
{
Message = "Dialog message",
OnConfirm = (result) =>
{
if (result)
{
AnotherService.Method();
}
}
});
}
In my tests I have the UserDialogsMock and AnotherServiceMock. I'm trying to setup the UserDialogsMock like below.
UserDialogsMock.Setup(s => s.Confirm(It.IsAny<ConfirmConfig>()))
.Callback((ConfirmConfig confirmConfig) => confirmConfig.OnConfirm(true));
How to verify that AnotherServiceMock.Method is invoked?
If AnotherServiceMock is injected, just verify it as normal:
AnotherServiceMock.Verify(s => s.Method(), Times.Once());
Here's a SSCCE that works for me:
namespace ConsoleApplication
{
using System;
using Moq;
using NUnit.Framework;
public class MoqCallbackTest
{
[Test]
public void TestMethod()
{
Mock<IAnotherService> mockAnotherService = new Mock<IAnotherService>();
Mock<IUserDialogs> mockUserDialogs = new Mock<IUserDialogs>();
mockUserDialogs.Setup(s => s.Confirm(It.IsAny<ConfirmConfig>()))
.Callback((ConfirmConfig confirmConfig) => confirmConfig.OnConfirm(true));
SystemUnderTest systemUnderTest = new SystemUnderTest(mockUserDialogs.Object,
mockAnotherService.Object);
systemUnderTest.ViewModelMethod();
mockAnotherService.Verify(p => p.Method(), Times.Never());
}
public interface IAnotherService
{
void Method();
}
public interface IUserDialogs
{
void Confirm(ConfirmConfig config);
}
public class ConfirmConfig
{
public Action<bool> OnConfirm { get; set; }
}
public class SystemUnderTest
{
readonly IAnotherService anotherService;
readonly IUserDialogs userDialogs;
public SystemUnderTest(IUserDialogs userDialogs, IAnotherService anotherService)
{
this.userDialogs = userDialogs;
this.anotherService = anotherService;
}
public void ViewModelMethod()
{
userDialogs.Confirm(new ConfirmConfig { OnConfirm = result =>
{
if (result)
anotherService.Method();
} });
}
}
}
}

Categories

Resources