I've been searching the web for a way to make an IEnumerable in the Setup of a Mock by converting the Values of my IDictionary to it (either directly or conversion from '=List to IEnumerable). However I have only come across the latter.
Inspiration Sources:
IEnumerable<object> a = new IEnumerable<object>(); Can i do this?
Convert dictionary with List to IEnumerable
Convert dictionary of any type to IEnumerable collection
How to use Moq to return a List of data or values?
public class UserServiceTests
{
private Mock<IUserRepository> _userRep { get; set; }
// fake app repository to get data from
private IDictionary<int, User> _userRepData { get; set; }
private UserService _sut { get; set; }
public UserServiceTests()
{
_userRepData = new Dictionary<int, User>();
_userRep = new Mock<IUserRepository>();
// Been able to create the proper list using:
// List<User> usersList = _userRepData.Values.ToList<User>();
// IEnumerable<User> users = appsList.AsEnumerable();
// So I am looking for away to replicate this in my setup method
// Obviously know the below is not the correct syntax.
_userRep.Setup(r => r.GetUsers()).Returns(() => new IEnumerable<User> {_userRepData.Values.ToList<User>} );
_sut = new UserService(_userRep.Object);
}
[Fact]
public void GetUsers_succeeds_at_getting_all_users_from_repository()
{
User user1 = new User();
User user2 = new User();
_userRepData.Add(1, user1);
_userRepData.Add(2, user2);
IEnumerable<User> users = new User[] { user1, user2 };
_sut.GetUsers().Should().BeSameAs(users); // Note: fluentassertions
}
}
Values already implements IEnumerable<T>.
You can return it directly; you don't need to create anything.
Related
I'm trying to actually test my code for once, but mocking has always been (one of) my Achilles Heel(s).
I'm doing some stuff with AD, and want to test without actually touch it. Here's what I'm doing:
var userPrincipalMock = new Mock<UserPrincipal>();
userPrincipalMock.Setup(x => x.SamAccountName).Returns("somesamaccountname");
userPrincipalMock.Setup(x => x.EmployeeId).Returns("anemployeenumber");
But apparently UserPrincipal doesn't wanna give up control of a samaccount name that easily:
Message "Unsupported expression: x => x.SamAccountName\nNon-overridable members (here: Principal.get_SamAccountName) may not be used in setup / verification expressions."
Any of you lovely guys or gals know the right way to go about this?
It is impossible to test methods that aren't marked as virtual. For this reason only interfaces should be mocked. To solve your problem, you can create a wrapper:
interface IUserPrincipalWrapper
{
string SamAccountName { get; set; }
string EmployeeId { get; set; }
void Delete();
... // Add all methods and properties of UserPrincipal that you need
}
class UserPrincipalWrapper : IUserPrincipalWrapper
{
private UserPrincipal Implementation { get; }
UserPrincipalWrapper(UserPrincipal implementation)
{
Implementation = implementation;
}
public string SamAccountName
{
get => Implementation.SamAccountName;
set => Implementation.SamAccountName = value;
}
public string EmployeeId
{
get => Implementation.EmployeeId;
set => Implementation.EmployeeId = value;
}
public void Delete()
{
Implementation.Delete();
}
...
// Call or set everything to Implementation...
// This is needed to create an interface around UserPrincipal, which you can mock
}
// Factory is needed for mocking `new` calls..
// as often times, you don't want to test that either
interface IUserPrincipalFactory
{
IUserPrincipalWrapper Create(PrincipalContext context);
}
class UserPrincipalFactory : IUserPrincipalFactory
{
public IUserPrincipalWrapper Create(PrincipalContext context)
{
var implementation = new UserPrincipal(context);
return new UserPrincipalWrapper(implementation);
}
}
Then in your tests you can mock everything:
// This is your mock
var userPrincipalMock = new Mock<IUserPrincipalWrapper>();
// You need factory for mocking `new UserPrincipal();` calls
var factoryMock = new Mock<IUserPrincipalWrapperFactory>();
factoryMock.Setup(factory => factory.Create(It.IsAny<PrincipalContext>())).Returns(userPrincipalMock.Object);
// Now it works :)
userPrincipalMock.Setup(x => x.SamAccountName).Returns("somesamaccountname");
userPrincipalMock.Setup(x => x.EmployeeId).Returns("anemployeenumber");
So I am trying again using a different controller to test a Cocoa desktop application using NUnit and Moq. The problem is, even after the .add() operation, I still don't have what I just added using the mock. More exactly, this is how I do the mock:
User user = new User
{
email = "test#gmail.com",
password = "1",
firstName = "Test",
lastName = "Test"
};
List<User> dataSource = new List<User>();
var userServiceMock = new Mock<IUserService>(MockBehavior.Strict);
userServiceMock.Setup(x => x.add(It.IsAny<User>()));
userServiceMock.Setup(x => x.getAllUsers()).Returns(dataSource);
var controller = new CreateAccountCoreController(userServiceMock.Object);
//act
controller.submit();
//assert
Assert.That(dataSource.Contains(user));
and in controller is this:
readonly IUserService userService;
public CreateAccountCoreController(IUserService userService)
{
this.userService = userService;
}
public void submit()
{
User user = new User
{
email = "test#gmail.com",
password = "1234",
firstName = "Test",
lastName = "Test",
};
userService.add(user);
List<User> users = userService.getAllUsers();
/*users it is empty here..*/
}
So my test always fails because the list of Users it is empty even after .add operation. Can you help please?
There is no place where you fill dataSource collection and you configure your mock to return it from getAllUsers() mock. So you will always get an empty collection from a method.
Use Callback() method to configure expected behavior:
userServiceMock.Setup(x => x.add(It.IsAny<User>())).Callback((User u) => dataSource.Add(u));
The second problem may be in comparing users in Contains() method. You need to tell Contains what makes two users equal. By default it will use ReferenceEquals which will only call two objects equal if they are the same instance.
Either override Equals and GetHashCode in your User class or define an IEqualityComparer<User> class and pass that to Contains.
If two Users that have the same email are "equal" then the implementation is pretty straightforward:
public override bool Equals(object o)
{
if(o.GetType() != typeof(User))
return false;
return this.email == ((User)o).email;
}
public override int GetHashCode()
{
return email.GetHashCode();
}
You can read more about value equality for a type.
I have some code I am trying to convert. I don't have these ObjectResult and ObjectContext anymore
This is what I did have:
public virtual ObjectResult<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new ObjectParameter("IN_MEM_ID", iN_MEM_ID) :
new ObjectParameter("IN_MEM_ID", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("GetTransData", iN_MEM_IDParameter);
}
Since I need a List to be returned from a caller ( it is sent back as json data )
This is what I am trying to build
public virtual List<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new SqlParameter("IN_MEM_ID", iN_MEM_ID) :
new SqlParameter("IN_MEM_ID", typeof(string));
Clinical_CaseTrakker_Context clinical = new Clinical_CaseTrakker_Context();
List<string> offLine = clinical.string.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter);
return offLine;
}
Notice that I am stuck with clinical.string i can't do that , but I am not sure how to take dbcontext instance and run FromSql to execute sql and return to List
In EF Core, it is not possible to use the FromSql method to return a subset of properties (a projection) directly from the database.
You are required to define a some model and a DbSet for that class
public class Foo
{
public string Bar { get; set; }
}
then declare in your context
public DbSet<Foo> Foos { get; set; }
and use it like:
using (var context = new Clinical_CaseTrakker_Context())
{
var offLine = context.Foos
.FromSql($"EXECUTE CT.GetTransData {iN_MEM_IDParameter}")
.Select(x => x.Bar)
.ToList();
return offLine;
}
Your Context needs a virtual DbSet<string> ResultStrings { get; set; } that you can call upon and put the result in. (This does not work, see this post or Roman Marusyk comment below)
EDIT: Your Context needs a virtual DbSet<ResultEntity> ResultEntities { get; set; } that you can call upon and put the result in.
Then you can do return clinical.ResultEntities.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter").toList() to fill the set.
Considering the ResultEntity has an Id and a value property, you can do ResultEntities.Select(e => e.value).toList() to extract a list of strings from the set.
I'm writing some unit tests and have a class called Account which has
public Guid AccountId {get;set;}
public IEnumerable<string> EmailAddresses {get;set;}
etc...
I want to use autofixture to create the account, but I'm having trouble getting the email format.
I have tried
fixture.Register<string>(() => string.Format("{0}#acme.com", fixture.Create<string>()));
but that that leads to circular problem.
I could do this
fixture.Register<string>(() => string.Format("{0}#acme.com", fixture.Create<int>()));
But I'd rather have a string at the start of the address.
EDIT
Thanks to both answers I have a written up a summary and few other scenarios as a post here - http://nodogmablog.bryanhogan.net/2016/04/customizing-a-specific-string-inside-a-class-using-autofixture/
There are a couple of ways of doing that. Here's one of them:
Assuming that MyClass is defined as
public class MyClass
{
public Guid AccountId { get; set; }
public IEnumerable<string> EmailAddresses { get; set; }
}
Then, a Fixture object can be customized like so
var fixture = new Fixture();
fixture.Customize<MyClass>(c => c
.With(x =>
x.EmailAddresses,
fixture.CreateMany<MailAddress>().Select(x => x.Address)));
var result = fixture.Create<MyClass>();
And so the EmailAddresses will be filled with email strings that look like:
"18e743af-89ae-46b7-b38e-ff51425ec745#example.org"
"928bd85d-7d89-4cca-bff3-a12d5da6fe29#example.org"
"61db1178-8af9-489f-ba44-95c6393d84a9#example.com"
This is one of those situations where AutoFixture is giving you feedback on the usability of your object model.
If the EmailAddresses property is supposed to only contain valid email addresses, then you should ask yourself whether representing them as generic strings is the right choice. A more specific type like the MailAddress class would restrict the set of valid values for that property.
It would also make it easier to generate test data for it, since AutoFixture knows how to create instances of MailAddress.
Having said that, if it's not feasible for you to change the object model, you can still write a customization that tells AutoFixture to provide valid email addresses for any property or parameter of type IEnumerable<string> with email somewhere in their name:
public class EmailAddressStringsGenerator : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
if (IsEnumerableOfStringPropertyOrParameterNamedEmail(request))
{
return CreateManyEmailAddresses(context);
}
return new NoSpecimen();
}
static bool IsEnumerableOfStringPropertyOrParameterNamedEmail(object request)
{
return IsEnumerableOfStringPropertyNamedEmail(request) ||
IsEnumerableOfStringParameterNamedEmail(request);
}
static bool IsEnumerableOfStringPropertyNamedEmail(object request)
{
var property = request as PropertyInfo;
return property != null &&
property.Name.ContainsIgnoringCase("email") &&
typeof(IEnumerable<string>).IsAssignableFrom(property.PropertyType);
}
static bool IsEnumerableOfStringParameterNamedEmail(object request)
{
var parameter = request as ParameterInfo;
return parameter != null &&
parameter.Name.ContainsIgnoringCase("email") &&
typeof(IEnumerable<string>).IsAssignableFrom(parameter.ParameterType);
}
static IEnumerable<string> CreateManyEmailAddresses(ISpecimenContext context)
{
var addresses = (IEnumerable<MailAddress>)
context.Resolve(typeof(IEnumerable<MailAddress>));
return addresses.Select(a => a.Address);
}
}
You can then use that customization in a Fixture by adding it to the Customizations property:
fixture.Customizations.Insert(0, new EmailAddressStringsGenerator());
From Autofixture
var localPart = fixture.Create<EmailAddressLocalPart>().LocalPart;
var domain = fixture.Create<DomainPart>().Domain;
var fullAddress = $"{localPart}#{domain}";
I know that a var is only in scope within it's method. But I've came across the situation where the collection 'var' from a database connection method, needs to be accessed in a subsequent Query() method in order to make a query.
The specific error is: The name collection doesn't exist in the current context
I've been referencing the MongoDB C# driver docs in order to set up the connection and the query and all seems correct besides this issue.
Does anyone know how I can restructure my code to resolve the error?
My two methods are specified as follows in an OrderRespository class, that makes database connections and queries:
//Method to create MongoDB Orders connection and get handle on collections
public static bool CreateConnection()
{
var client = new MongoClient(connectionString);
try
{
var database = client.GetDatabase("orders");
//Get a handle on the customers collection:
var collection = database.GetCollection<BsonDocument>("customers");
}
catch(MongoConnectionException)
{
return false;
}
return true;
}
//Method to test query on database documents
public async static Task<List<Customer>> FindCustomers()
{
var documents = await collection.Find(new BsonDocument()).ToListAsync();
List<Customer> customerList = await documents.ToListAsync();
return await documents.ToListAsync();
}
And this is the customer Model POCO class that models the collection fields:
public class Customer
{
/// <summary>
/// This attribute is used to map the Id property to the ObjectId in the collection
/// </summary>
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("firstName")]
public string firstName { get; set; }
[BsonElement("lastName")]
public string lastName { get; set; }
[BsonElement("email")]
public string Email { get; set; }
}
CreateConnection should return the collection that it's creating so that the person creating the connection can actually use it:
//Consider renaming this method; you're really here to get the customers,
//not create a connection
public static YourCollectionType<BsonDocument> CreateConnection()
{
var client = new MongoClient(connectionString);
var database = client.GetDatabase("orders");
//Get a handle on the customers collection:
return database.GetCollection<BsonDocument>("customers");
}
FindCustomers can then accept the collection as a parameter:
public async static Task<List<Customer>> FindCustomers(
YourCollectionType<BsonDocument> collection)
{
var documents = await collection.Find(new BsonDocument()).ToListAsync();
List<Customer> customerList = await documents.ToListAsync();
return await documents.ToListAsync();
}
You can then use CreateConnection to create the documents that you search through:
var customers = FindCustomers(CreateConnection());
If FindCustomers is something that would only ever make sense to use with a collection created by CreateConnection and you won't ever use the created object for anything else, then you could have FindCustomer call CreateConnection directly, but odds are those conditions won't apply.