How can I mock the Azure Redis Cache?
I would like to write unit test for one of my application which uses Azure Redis Cache. Since I am completely new to mocking and stubbing in writing unit test code, I am looking for help in how I can start with the basic script for mocking/stubbing cache component.
Testing with external resources like databases, files, and caches is integration testing, non unit. What you can test in unit-tests is the fact, that your code is calling caching methods.
So, first, you need an interface of cache service. This interface not only let you test your code, but also let you use different caching servers.
public interface ICache
{
void Add<T>(string key, TimeSpan lifetime, T value);
bool TryGet<T>(string key, out T value);
void Remove(string key);
. . .
}
Second, you need domain code to test:
public class SleepingMembersService
{
private readonly TimeStamp _lifetime = TimeStamp.FromMinutes(5);
private readonly ICache _cache;
private readonly INotifier _notifier;
public SleepingMembersService(ICache cache, INotifier notifier)
{
_cache = cache;
_notifier = notifier;
}
private string MakeKey(User user) => $"unsleepingUser{user.Id}";
public void WakeUpIfSleep(IUser user)
{
var key = MakeKey(user);
bool isWaking;
if (_cache.TryGet(key, out isWaking) && isWaking)
return;
notifier.Notify(user.Id, "Wake up!");
}
public void ConfirmImNotSleeping(IUser user)
{
var key = MakeKey(user);
_cache.Add(key, _lifeTime, true);
}
}
Third, let's make stub cache:
public class StubCache : ICache
{
public bool TryGetResult { get; set; }
public bool TryGetValue { get; set; }
public bool AddValue { get; set; }
public TimeStamp LifeTimeValue { get; set; }
void Add<T>(string key, TimeSpan lifetime, T value)
{
LifeTimeValue = lifetime;
AddValue = (bool)(object)value;
}
bool TryGet<T>(string key, out T value)
{
value = (T)(object)TryGetValue;
return TryGetResult;
}
. . .
}
And finally you can write unit-test:
pubic void ConfirmImNotSleeping_WhenCalled_CallsAdd()
{
var cache = new StubCache<bool>();
var notifier = new StubNotifier();
var service = new SleepingMembersService(cache, notifier);
var user = new StubUser(1, "John Doe");
service.ConfirmNotSleeping(user);
Assert.IsTrue(cache.AddValue);
}
Well, you've checked that the method ConfirmNotSleeping calls the method Add.
Now, you should implement ICache for Redis:
public RedisCache : ICache
{
private IConnectionMultiplexer connection;
public bool TryGet<T>(string key, out T value)
{
var cache = Connection.GetDatabase();
var rValue = cache.StringGet(key);
if (!rValue.HasValue)
{
value = default(T);
return false;
}
value = JsonConvert.DeserializeObject<T>(rValue);
return true;
}
. . .
}
To simplify implement stubs and mocks you can use libraries like Moq. These libraries let you automatically generate stubs and mocks for your purpose. So you test code will look like this:
pubic void ConfirmImNotSleeping_WhenCalled_CallsAdd()
{
var cacheStub = new Mock<ICache>();
var notifierStub = new Mock<INotifier>();
var service = new SleepingMembersService(cache.Object, notifier.Object);
var userStub = new Mock<IUser>();
service.ConfirmNotSleeping(user.Object);
cacheStub.Vertify(x => x.Add(It.IsAny<string>(), It.IsAny<TimeStamp>(), true));
}
Related
Question
How do I define an incoming Type T constraint that will allow me to call a static method on the class (of type T) to get the intended IndexModel object for passing to Mongo?
Background
I'm currently trying to write a Mongo Provider class that will allow me to ensure my particular database and collection are present before doing any operations with them, since there is a potential that the container or server it resides in could be destroyed and recreated at any time, and I'd prefer to have a safe way in code to ensure that the external dependency is there (instance is beyond my control, so I have to trust that something is there).
One of the things I'm trying to do, since I've managed to do what I stated above for Database and Collection instantiation, is to also generate indexes. My idea was to have a static method on the classes that would return their specific definition of an index model. This way, each class would be responsible for their own Mongo indexes, rather than some convoluted switch-case statement in my Provider based on the incoming type of T.
My first idea was to have an interface that shared this method, but Interfaces don't allow you to declare a static method. Similarly, I tried an Abstract Base-class and found that the static implementation would call the base class that defined the method, rather than any overrides in an inheritor.
Sample Code
public class MyClass
{
public DateTime DateValue { get; set; }
public int GroupId { get; set; }
public string DataType { get; set; }
public static IEnumerable<CreateIndexModel<MyClass>> GetIndexModel(IndexKeysDefinitionBuilder<MyClass> builder)
{
yield return new CreateIndexModel<MyClass>(
builder.Combine(
builder.Descending(entry => entry.DateValue),
builder.Ascending(entry => entry.GroupId),
builder.Ascending(entry => entry.DataType)
)
);
}
}
Edit
I guess I should probably include a shell of my Mongo Provider class. See below:
Edit #2 due to questions about how this hasn't solved my problem, I'm updating the MongoProvider to have the problematic code. Note: Once this method is included, the class will no longer compile, since it isn't possible given what I've done thus far.
public class MongoProvider
{
private readonly IMongoClient _client;
private MongoPrivder(ILookup<string, string> lookup, IMongoClient client)
{
_client = client;
foreach(var database in lookup)
foreach(var collection in database)
Initialize(database.Key, collection);
}
public MongoProvider(IConfiguration config) :this(config.GetMongoObjects(), config.GetMongoClient())
{}
public MongoProvider(IConfiguration config, IMongoClient client) : this(config.GetMongoObjects(), client)
{}
private void Initialize(string database, string collection)
{
var db = _client.GetDatabase(database);
if (!db.ListCollectionNames().ToList().Any(name => name.Equals(collection)))
db.CreateCollection(collection);
}
// The Problem
private void InitializeIndex<T>(string database, string collection)
{
IEnumerable<CreateIndexModel<T>> models;
switch (T)
{
case MyClass:
model = MyClass.GetIndexModel();
break;
default:
break;
}
await _client.GetDatabase(database)
.GetCollection<T>(collection)
.Indexes
.CreateManyAsync(models);
}
}
Edit #3
As a stop-gap, I've gone ahead and done something terrible (not sure if it's going to work yet), and I'll supply the example so you can know my best solution thus far.
public static class Extensions
{
#region Object Methods
public static T TryCallMethod<T>(this object obj, string methodName, params object[] args) where T : class
{
var method = obj.GetType().GetMethod(methodName);
if (method != null)
{
return method.Invoke(obj, args) as T;
}
return default;
}
#endregion
}
This allows me to do the following (inside of MongoProvider)
private async void InitializeIndex<T>(string database, string collection) where T : new()
{
var models = new T().TryCallMethod<IEnumerable<CreateIndexModel<T>>>("GetIndexModel");
await _client.GetDatabase(database)
.GetCollection<T>(collection)
.Indexes
.CreateManyAsync(models);
}
Since it doesn't look like I'm going to get an answer to this, I figured I would provide my solution for future searches of this question. Basically, I added an extension method to the base object class, and used reflection to determine if the method I was looking for was there. From there, I returned a value of true or false, depending on if the method was found, and output the return value to a parameter, in the traditional TryGet pattern.
Note to Future Readers
I do not recommend this approach. This is just how I solved my problem for accessing a method on a type of T. Ideally, an instance method would be implemented, and a signature defined in a common Interface, but that wasn't going to work for my use case.
My Answer
public static class Extensions
{
#region Object Methods
public static bool TryCallMethod<T>(this object obj, string methodName, out T result, params object[] args) where T : class
{
result = null;
var method = obj.GetType().GetMethod(methodName);
if (method == null)
return false;
result = method.Invoke(obj, args) as T;
return true;
}
#endregion
}
My data class looks like this (obfuscated from actual usage)
[BsonDiscriminator("data")]
public class DataClass
{
#region Private Fields
private const string MongoCollectionName = "Data";
#endregion
#region Public Properties
public string CollectionName => MongoCollectionName;
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("date_value")]
public DateTime DateValue { get; set; }
[BsonElement("group_id")]
public int GroupId { get; set; }
[BsonElement("data_type")]
public string DataType { get; set; }
[BsonElement("summary_count")]
public long SummaryCount { get; set; }
[BsonElement("flagged_count")]
public long FlaggedCount { get; set; }
[BsonElement("error_count")]
public long ErrorCount { get; set; }
#endregion
#region Constructor
public DataClass()
{
}
public DataClass(int groupId, string dataType = null, long summaryCount = 0, long flaggedCount = 0, long errorCount = 0)
{
Id = ObjectId.GenerateNewId();
DateValue = DateTime.UtcNow;
GroupId = groupId;
DocCount = summaryCount;
DataType = dataType ?? "default_name";
FlaggedCount = flaggedCount;
ErrorCount = errorCount;
}
#endregion
#region Public Methods
public static IEnumerable<CreateIndexModel<AuditEntry>> GetIndexModel(IndexKeysDefinitionBuilder<AuditEntry> builder)
{
yield return new CreateIndexModel<AuditEntry>(
builder.Combine(
builder.Descending(entry => entry.DateValue),
builder.Ascending(entry => entry.GroupId),
builder.Ascending(entry => entry.DataType)
)
);
}
#endregion
}
I would then call the method in the following fashion, inside my MongoProvider class. The ellipses are present to identify that more code exists within the class.
public class MongoProvider : IMongoProvider
{
#region Private Fields
private readonly IMongoClient _client;
#endregion
#region Constructor
...
#endregion
#region Private Methods
private void Initialize(string database, string collection)
{
var db = _client.GetDatabase(database);
if (!db.ListCollectionNames().ToList().Any(name => name.Equals(collection)))
db.CreateCollection(collection);
}
private async Task InitializeIndex<T>(string database, string collection) where T : new()
{
if(new T().TryCallMethod<IEnumerable<CreateIndexModel<T>>>("GetIndexModel", out var models, new IndexKeysDefinitionBuilder<T>()))
await _client.GetDatabase(database)
.GetCollection<T>(collection)
.Indexes
.CreateManyAsync(models);
}
private static void ValidateOptions<T>(ref FindOptions<T, T> options)
{
if(options != null)
return;
options = new FindOptions<T, T>
{
AllowPartialResults = null,
BatchSize = null,
Collation = null,
Comment = "AspNetWebService",
CursorType = CursorType.NonTailable,
MaxAwaitTime = TimeSpan.FromSeconds(10),
MaxTime = TimeSpan.FromSeconds(10),
Modifiers = null,
NoCursorTimeout = false,
OplogReplay = null
};
}
private static FilterDefinition<T> GetFilterDefinition<T>(Func<FilterDefinitionBuilder<T>, FilterDefinition<T>>[] builders)
{
if(builders.Length == 0)
builders = new Func<FilterDefinitionBuilder<T>, FilterDefinition<T>>[] {b => b.Empty};
return new FilterDefinitionBuilder<T>()
.And(builders
.Select(b => b(new FilterDefinitionBuilder<T>()))
);
}
#endregion
#region Public Methods
public async Task<IReadOnlyCollection<T>> SelectManyAsync<T>(string database, string collection, FindOptions<T, T> options = null, params Func<FilterDefinitionBuilder<T>, FilterDefinition<T>>[] builders) where T : new()
{
ValidateOptions(ref options);
await InitializeIndex<T>(database, collection);
var filter = GetFilterDefinition(builders);
var find = await _client.GetDatabase(database)
.GetCollection<T>(collection)
.FindAsync(filter, options);
return await find.ToListAsync();
}
...
#endregion
}
In my asp.net core 2 application, I have a static class which handles some interactions with the session. For example :
public static class BookManager
{
private const string Key = "Books";
public static HttpContextAccessor ContextAccessor => new HttpContextAccessor();
public static void AddBooksToContainer(IEnumerable<BookViewModel> books)
{
ContextAccessor.HttpContext.Session.Set(Key, books);
}
public static IEnumerable<BookViewModel> GetBooks()
{
return ContextAccessor.HttpContext.Session.Get<IEnumerable<BookViewModel>>(Key);
}
}
I have also added some extension methods to the session object :
public static class SessionExtensions
{
public static void Set<T>(this ISession session, string key, IEnumerable<T> value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) :
JsonConvert.DeserializeObject<T>(value);
}
}
Update: This is how i try to mock :
var bookList = new List<BookViewModel>()
{
new BookViewModel {Author = "test", Id = Guid.NewGuid(), InStock = 1, Price = 1000, Title = "tes"}
};
var httpContextAccessor = new Mock<IHttpContextAccessor>().SetupAllProperties();
httpContextAccessor.Setup(x => x.HttpContext.Session.Get<IEnumerable<BookViewModel>>("test")).Returns(bookList);
And the error i get :
System.NotSupportedException : Invalid setup on an extension method: x =>
x.HttpContext.Session.Get<IEnumerable`1>("test")
The problem is I have tried many ways to mock session and its extension methods but I got no result yet. many ways work in .netframework and not core.
I use xunit for testing and Moq library to mock the objects. Please tell me how can I mock session and its extension methods. Appreciate it.
The problem is not related to .NET Core, is a limitation of the mocking library, you can't mock extension methods with Moq.
This might help: Mocking Extension Methods with Moq
Depend on abstractions and not concretions. Create a Factory method that will provide you with the IHttpContextAccessor abstraction.
public static class BookManager {
private const string Key = "Books";
public static Func<IHttpContextAccessor> ContextAccessor = () => new HttpContextAccessor();
public static void AddBooksToContainer(IEnumerable<BookViewModel> books) {
ContextAccessor().HttpContext.Session.Set(Key, books);
}
public static IEnumerable<BookViewModel> GetBooks() {
return ContextAccessor().HttpContext.Session.Get<IEnumerable<BookViewModel>>(Key);
}
}
This will allow you to replace the abstraction when testing with a mock.
//Arrange
var mock = mock.Of<IHttpContextAccessor>();
BookManager.ContextAccessor = () => {
return mock.Object;
};
//...
Better yet if this manager only has need of the session then do not expose more than it needs.
public static class BookManager {
private const string Key = "Books";
public static Func<ISession> Session = () => new HttpContextAccessor().HttpContext.Session;
public static void AddBooksToContainer(IEnumerable<BookViewModel> books) {
Session().Set(Key, books);
}
public static IEnumerable<BookViewModel> GetBooks() {
return Session().Get<IEnumerable<BookViewModel>>(Key);
}
}
So now only the explicit dependencies need to be mocked for tests.
According to ISession Extensions source code GetString and SetString are also extension methods
You will need to mock ISession.TryGetValue and ISession.Set
//Arrange
var mock = Mock.Of<ISession>();
BookManager.Session = () => {
return mock;
};
var value = Encoding.UTF8.GetBytes("[{some books json strings here}]");
Mock.Get(mock).Setup(_ => _.TryGetValue("Books", out value))
.Returns(true);
//Act
var books = BookManager.GetBooks();
//...
I'm kinda new in using of Castle Windsor, and didn't find relevant answers.
Lets say I have some interface
public interface IStoreServiceCache
{
void Put(string key, object value);
T Get<T>(string key);
}
And few implementations:
Main calls that responsible for StoreServiceCache:
public class StoreServiceCache : IStoreServiceCache
{
private readonly IStoreServiceCache _cacheRef;
public StoreServiceCache(IStoreServiceCache concreteCache)
{
_cacheRef = concreteCache;//Container.Instance.Resolve<IStoreServiceCache>("FileCache");//new StoreServiceFileCache());
LoadStoreDetailData();
}
public void Put(string key, object value)
{
_cacheRef.Put(key, value);
}
public T Get<T>(string key)
{
return _cacheRef.Get<T>(key);
}
private void LoadStoresDetailData()
{
// Read from some file and fill cache
}
}
And some specific for FileCache
internal class StoreServiceFileCache : IStoreServiceCache
{
private readonly FileCache cache;
public StoreServiceFileCache()
{
string cacheEndPoint = "CacheEndpoint";
string cacheAuthToken = "CacheAuthToken";
cache = FilesCacheFactory.Get(cacheEndPoint, cacheAuthToken);
}
public void Put(string key, object value)
{
cache.Put(key.ToLower(), value);
}
public T Get<T>(string key)
{
T result;
cache.Get(key.ToLower(), out result);
return result;
}
}
Now, my Windsor intsaller looks like this
var container = new WindsorContainer();
container.Register(Component.For<IStoreServiceCache>().ImplementedBy<StoreServiceCache>()
.DependsOn(Dependency.OnComponent(typeof(IStoreServiceCache), "FileCache")).LifestyleSingleton());
container.Register(Component.For<IStoreServiceCache>().Named("FileCache").ImplementedBy<StoreServiceFileCache>());
Few questions:
For now if I call StoreServiceCache, it will use StoreServiceFileCache inside. And what if I also want to create StoreServiceCach, that will use another concrete cache (e.g. StoreServiceWebCache). How can I configure it with Castle.
If I want to use some DummyCache in my unit test. So for example, I'll create DummyCache that can load data to that cache and when I'll run unit test it will use the real data.
I have a class that calls out to an internet service to get some data:
public class MarketingService
{
private IDataProvider _provider;
public MarketingService(IDataProvider provider)
{
_provider = provider;
}
public string GetData(int id)
{
return _provider.Get(id);
}
}
Currently I have two providers: HttpDataProvider and FileDataProvider. Normally I will wire up to the HttpDataProvider but if the external web service fails, I'd like to change the system to bind to the FileDataProvider . Something like:
public string GetData(int id)
{
string result = "";
try
{
result = GetData(id); // call to HttpDataProvider
}
catch (Exception)
{
// change the Windsor binding so that all future calls go automatically to the
// FileDataProvier
// And while I'm at it, retry against the FileDataProvider
}
return result;
}
So when this has been executed all future instances of MarketingService will automatically be wired up to the FileDataProvider. How to change a Windsor binding on the fly?
One solution would be using selector
public class ForcedImplementationSelector<TService> : IHandlerSelector
{
private static Dictionary<Type, Type> _forcedImplementation = new Dictionary<Type, Type>();
public static void ForceTo<T>() where T: TService
{
_forcedImplementation[typeof(TService)] = typeof(T);
}
public static void ClearForce()
{
_forcedImplementation[typeof(TService)] = null;
}
public bool HasOpinionAbout(string key, Type service)
{
return service == typeof (TService);
}
public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
{
var tService = typeof(TService);
if (_forcedImplementation.ContainsKey(tService) && _forcedImplementation[tService] != null)
{
return handlers.FirstOrDefault(handler => handler.ComponentModel.Implementation == _forcedImplementation[tService]);
}
// return default
return handlers[0];
}
}
Test and usage
[TestFixture]
public class Test
{
[Test]
public void ForceImplementation()
{
var container = new WindsorContainer();
container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
container.Register(Component.For<IFoo>().ImplementedBy<Bar>());
container.Kernel.AddHandlerSelector(new ForcedImplementationSelector<IFoo>());
var i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Foo), i.GetType());
ForcedImplementationSelector<IFoo>.ForceTo<Bar>();
i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Bar), i.GetType());
ForcedImplementationSelector<IFoo>.ClearForce();
i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Foo), i.GetType());
}
}
Alternatively you could create a proxy:
public class AutoSelectingDataProvider : IDataProvider
{
public AutoSelectingDataPovider(HttpDataProvider httpDataProvider, FallBackDataProvider fallBackProvider)
{
_httpDataProvider = httpDataProvider;
_fallBackDataProvider = fallBackDataProvider;
}
public string GetData(int id)
{
try
{
return _httpDataProvider.GetData(id);
}
catch (Exception)
{
return _fallBackDataProvider.GetData(id);
}
return result;
}
}
container.Register(
Component.For<HttpDataProvider>(),
Component.For<FallBackDataProvider>(),
Component.For<IDataProvider>().ImplementedBy<FallBackDataProvider>());
This will always first try to get data from the HttpDataProvider if not succesfull use the fallback. If you want you can introduce state and after a failure always use the fallback. This way you can keep using the IDataProvider in your application without needing to obtain a new one from the container.
I need to fake HttpContext.Current.Application table in order to access it from my unit tests.
I need to store my data somewhere. I thought that I can just pass instance of NameValueCollectionBase but as I discovered this base type has no indexer so it seems too complicated to use.
So what about faking this part of HttpContext? Is it possible? How can I make it? Will be NUnit.Mocks helpful?
Thank you in advance...
Please go through below links it will help you.
http://www.java2s.com/Open-Source/CSharp/Web-Frameworks/MvcContrib/MvcContrib/TestHelper/Fakes/FakeHttpContext.cs.htm
Mocking and HttpContextBase.get_User()
Thanks
Venkat
If you need indexes for namevaluecollection base please use below code
public static IEnumerable<KeyValuePair<string, string>> ToPairs(this NameValueCollection collection)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
return collection.Cast<string>().Select(key => new KeyValuePair<string, string>(key, collection[key]));
}
For just to store data and passing around test methods please use above code.
In this scenario I generate some stubs derived from the base classes in System.Web.Abstractions. I often use this technique for MVC applications as MVC / WebApi controllers contain an abstraction to HttpContext (HttpContextBase)
This way I can stub out HttpContext requirements in my unit / integration tests, here's a sample...
public class MockHttpApplicationState : HttpApplicationStateBase
{
private IDictionary<string, object> _appState = new Dictionary<string, object>();
public override void Add(string name, object value)
{
_appState.Add(name, value);
}
public override object Get(string name)
{
return _appState[name];
}
public override object this[string name]
{
get
{
return _appState[name];
}
set
{
_appState[name] = value;
}
}
}
public class MockHttpContext : HttpContextBase
{
private IDictionary<string, object> _appKeys;
public MockHttpContext()
{
}
/// <summary>
/// Accepts a dictionary of app keys to supply to the HttpApplicationState instance
/// </summary>
/// <param name="applicationState"></param>
public MockHttpContext(IDictionary<string,object> applicationState)
{
_appKeys = applicationState;
}
public override Cache Cache
{
get
{
return HttpRuntime.Cache;
}
}
public override HttpApplicationStateBase Application
{
get
{
var mockAppState = new MockHttpApplicationState();
foreach (string key in _appKeys.Keys)
{
mockAppState.Add(key, _appKeys[key]);
}
return mockAppState;
}
}
public override HttpRequestBase Request
{
get
{
return new HttpRequestWrapper(new HttpRequest(null,"http://localhost",null));
}
}
}
Then my test can establish Controller and Http Context:
private readonly OnlineShop.MVC.Controllers.HomeController _controller =
new MVC.Controllers.HomeController(null,new UnitOfWork());
[OneTimeSetUp]
public void Init()
{
var appKeys = new Dictionary<string, object>();
appKeys.Add("localhost", 1);
var httpContext = new MockHttpContext(appKeys);
_controller.ControllerContext = new ControllerContext()
{
Controller = _controller,
RequestContext = new RequestContext(httpContext, new RouteData())
};
}
[Test]
public void Index_Returns_HomeView()
{
var view = _controller.Index() as ViewResult;
var viewModel = view.Model as MVC.ViewModels.Home;
Assert.IsInstanceOf<OnlineShop.MVC.ViewModels.Home>(viewModel);
Assert.IsTrue(viewModel.FeaturedProducts.Count > 0);
}
And my controller is aware of it's ambient HttpContextBase instance supplying Cache and Application state:
public ActionResult Index()
{
string cacheKey = string.Format("FeaturedProducts-{0}",WebsiteId);
IList<Product> productList = this.HttpContext.Cache[cacheKey] as IList<Product>;
//My app keeps a list of website contexts in the Application. This test returns 1 based on the unit / int tests or a real world db value when hosted on IIS etc..
int websiteId = (int)HttpContext.Application[this.Request.Url.Host];