Mocking SubscriberServiceApiClient - is it possible? - c#

[Test]
public async Task TestSubscriber()
{
var subscriber = new Mock<SubscriberServiceApiClient>();
subscriber.Setup(x =>
x.PullAsync(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<CallSettings>()))
.ReturnsAsync(new PullResponse
{
ReceivedMessages =
{
new ReceivedMessage()
{
Message = new PubsubMessage
{
MessageId = "1",
PublishTime = DateTime.UtcNow.ToTimestamp(),
OrderingKey = "1"
}
}
}
});
var mySubscriber = new MySubscriber(subscriber.Object);
await mySubscriber.PullMessage(new CancellationToken());
}
public class MySubscriber
{
private SubscriberServiceApiClient _subscriberServiceApiClient;
...
public MySubscriber(SubscriberServiceApiClient subscriberServiceApiClient)
{
...
_subscriberServiceApiClient = subscriberServiceApiClient;
}
public async Task PullMessage(CancellationToken cancellationToken)
{
var messages = await _subscriberServiceApiClient.PullAsync("mysubscription", 10);
//always null
}
}
I don't see what I'm doing wrong here.
Is it possible to mock SubscriberServiceApiClient?

Related

Mongo time-series inserts using c# produce exception after short time

I want to test if mongo db can have a collection up to 50 000 000 000.
So I insert 10K elements every second using method:
public async Task InsertManyAsync(List<DBRoutLine> list)
{
await _collRouts.InsertManyAsync(list);
}
Data looks like this:
namespace DbLayer.Models
{
public class DBRoutLineMeta
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string id { get; set; }
public int counter { get; set; }
}
[BsonIgnoreExtraElements]
public class DBRoutLine
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string id { get; set; }
public DBRoutLineMeta meta { get; set; } = new DBRoutLineMeta();
public DateTime timestamp { get; set; } = DateTime.UtcNow;
public string some_data { get; set; } = DateTime.Now.ToString();
}
}
id members not required actually but I have them, just for testing.
So I've got exception like this:
"A bulk write operation resulted in one or more errors. WriteErrors: [ { Category : "DuplicateKey", Code : 11000, Message : "E11000 duplicate key error collection: TSTest.system.buckets.TSTable dup key: { _id: ObjectId('634e87301297fa65b7df9923') }" } ]."
after sometime. It can be also like this:
"time-series insert failed: TSTest.TSTable :: caused by :: Expected
And it will never recover from error even if I recreate connection to mongo server. Only application restart helps to insert records again.
Test code:
using DbLayer.Models;
using DbLayer.Services;
using MongoDB.Bson;
Console.WriteLine("Hello, World!");
var service = new RoutService();
try
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
var list = new List<DBRoutLine>();
for (int i = 0; i < 10000; i++)
{
DBRoutLine line = new DBRoutLine();
list.Add(line);
}
Task task = Task.Run(async () => {
int max_counter = await service.GetMaxCount();
bool recover = false;
while (!token.IsCancellationRequested)
{
try
{
if (!recover)
{
foreach (DBRoutLine line in list)
{
line.meta.counter = ++max_counter;
line.id = ObjectId.GenerateNewId().ToString();
line.meta.id = line.id;
}
}
var t1 = DateTime.Now;
await service.InsertManyAsync(list);
var t2 = DateTime.Now;
max_counter = await service.GetMaxCount();
var t3 = DateTime.Now;
Console
.WriteLine(
$"{max_counter}->Insert:{(int)(t2 - t1).TotalMilliseconds}, GetMax:{(int)(t3 - t2).TotalMilliseconds}");
recover = false;
}
catch(Exception ex)
{
recover = true;
await Task.Delay(3000);
Console.WriteLine(ex.Message.ToString());
service = new RoutService();
max_counter = await service.GetMaxCount();
}
}
}, token);
Console.WriteLine("Press any key to stop emulation\n");
Console.ReadKey();
tokenSource.Cancel();
Task.WaitAll(task);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Service code:
using DbLayer.Models;
using MongoDB.Bson;
using MongoDB.Driver;
namespace DbLayer.Services
{
public class RoutService:IDisposable
{
private readonly IMongoCollection<DBRoutLine> _collRouts;
private readonly MongoClient _mongoClient;
private readonly string CollName = "TSTable";
public RoutService(
)
{
var ConnectionString = "mongodb://mongoservice:27017";
_mongoClient = new MongoClient(
ConnectionString);
var mongoDatabase = _mongoClient.GetDatabase(
"TSTest");
var filter = new BsonDocument("name", CollName);
var options = new ListCollectionNamesOptions { Filter = filter };
if (!mongoDatabase.ListCollectionNames(options).Any())
{
var createOptions = new CreateCollectionOptions();
var timeField = nameof(DBRoutLine.timestamp);
var metaField = nameof(DBRoutLine.meta);
createOptions.TimeSeriesOptions =
new TimeSeriesOptions(timeField, metaField, TimeSeriesGranularity.Minutes);
mongoDatabase.CreateCollection(
CollName,
createOptions);
}
_collRouts =
mongoDatabase.GetCollection<DBRoutLine>(
CollName
);
CreateIndexes();
}
private void CreateIndexes()
{
{
IndexKeysDefinition<DBRoutLine> keys =
new IndexKeysDefinitionBuilder<DBRoutLine>()
.Descending(d => d.meta.counter);
var indexModel = new CreateIndexModel<DBRoutLine>(
keys, new CreateIndexOptions()
{ Name = "counter" }
);
_collRouts.Indexes.CreateOneAsync(indexModel);
}
////////////////////////////////////////////////
{
IndexKeysDefinition<DBRoutLine> keys =
new IndexKeysDefinitionBuilder<DBRoutLine>()
.Ascending(d => d.meta.id);
var indexModel = new CreateIndexModel<DBRoutLine>(
keys, new CreateIndexOptions()
{ Name = "id" }
);
_collRouts.Indexes.CreateOneAsync(indexModel);
}
}
public async Task InsertManyAsync(List<DBRoutLine> list)
{
await _collRouts.InsertManyAsync(list);
}
public async Task<int> GetMaxCount()
{
var last = await _collRouts
.Find(i=> i.meta.counter > 0)
.SortByDescending( i => i.meta.counter).FirstOrDefaultAsync();
if (last == null)
{
return 0;
}
return last.meta.counter;
}
public void Dispose()
{
}
}
}
project repository:
github.com/pruginkad/TestMongo
Ok, I found the bug. I changed timestamp only once when I created List of documents.
in this code:
foreach (DBRoutLine line in list)
{
line.meta.counter = ++max_counter;
line.id = ObjectId.GenerateNewId().ToString();
line.meta.id = line.id;
line.timestamp = DateTime.UtcNow;//missing line
}
I had to update timestamp, my mistake.
Anyway it's kind of strange that exception happen after every 17M documents and disappear after restart of mongo db

Autofac.Extras.Moq - response from mocked Login does not contain expected value

I want to make unit tests in my app. I use NUNIT, and the following libraries :
Autofac.Extras.Moq
AutoFixture
I followed this samples but it doesn't work :
http://makanda.io/unit-testing-xamarin-forms-view-model/
Mock a method of class under test with Moq & AutoMock
Here is my test :
private Fixture _fixture;
[SetUp]
public void Setup()
{
_fixture = new Fixture();
}
[Test]
public void Login_Success()
{
using (var mock = AutoMock.GetLoose())
{
var infosLogin = _fixture.Create<LoginRequest>();
var loginResponse = _fixture.Create<LoginResponse>();
var userService = mock.Mock<IUserService>();
userService
.Setup(user => user.Login(infosLogin))
.Returns(Task.FromResult(loginResponse));
var viewModel = new MainPageViewModel(new ContentPage(), userService.Object);
viewModel.Login = infosLogin.Username;
viewModel.Password = infosLogin.Password;
viewModel.LoginCommand.Execute(null);
}
}
My view
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel(this, new UserServiceImpl());
}
My ViewModel
public MainPageViewModel(Page page, IUserService userService)
{
_page = page;
_userService = userService;
Login = "";
Password = "";
}
public Command LoginCommand
{
get
{
return new Command(async () =>
{
Console.WriteLine("step 1...");
if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password))
{
Console.WriteLine("step 2...");
var infos = new LoginRequest() { Username = "Wyllis", Password = "test" };
LoginResponse response = await _userService.Login(infos);
Console.WriteLine("step 3...");
Console.WriteLine(response);
Age = response.Age; // Got error : Object reference not set to an instance of an object
}
});
}
}
LoginResponse model
public class LoginResponse
{
public string Username { get; set; }
public string Age { get; set; }
}
Age = response.Age;, I Got error : Object reference not set to an instance of an object, can you explain what is wrong ?
I found the solution, new LoginRequest(...) from my viewmodel and my tests are same BUT the hashcode (memory address) is different, so my test fail because my param is not the same object with the same memory than viewmodel
here is my new test and my view model
ViewModel
public Command LoginCommand
{
get
{
return new Command(async () =>
{
if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password))
{
var infos = new LoginRequest() { Username = Login, Password = Password };
LoginResponse response = await _userService.Login(infos);
Age = response.Age;
}
});
}
}
Test
private Mock<IUserService> _userService;
private MainPageViewModel _viewModel;
private Fixture _fixture;
[SetUp]
public void Setup()
{
using (var mock = AutoMock.GetLoose())
{
_userService = mock.Mock<IUserService>();
}
_fixture = new Fixture();
}
private MainPageViewModel CreateInstance()
{
return new MainPageViewModel(_userService.Object);
}
[Test]
public void Test_Constructor()
{
using (var mock = AutoMock.GetLoose())
{
var viewModel = mock.Create<MainPageViewModel>();
viewModel.Login.Equals("");
viewModel.Password.Equals("");
}
}
[Test]
public void Login_Success()
{
var user = _fixture.Create<LoginResponse>();
_viewModel = CreateInstance();
_viewModel.Login = "test";
_viewModel.Password = "test";
_userService
.Setup(s => s.Login(It.IsAny<LoginRequest>()))
.Returns(Task.FromResult(user))
.Verifiable();
_viewModel.LoginCommand.Execute(null);
_userService.Verify();
Assert.AreEqual(_viewModel.Age, user.Age);
}

data to come in while and this incoming data to be returned continuously

my purpose is, I want data to come in while and this incoming data to be returned continuously.
I put the AddValue ​​method in while because I want add data all the time.
and return the al the time
My Prblem is i call the GetValues in Hub but its returned to null
i try the so many various
public class StockCaller
{
public static ConcurrentDictionary<string, Stock> _stock = new ConcurrentDictionary<string, Stock>();
public async Task AddValue()
{
while (true)
{
string[] symbols = new string[6] { "USD", "EUR", "ATLAS", "GARAN", "ISBNK", "AKBNK" };
Random random = new Random();
foreach (var item in symbols)
{
Stock stock = new Stock()
{
symbol = item,
price = random.Next(100, 500),
percent = random.NextDouble(),
};
await AddValueAsync(stock);
}
}
}
public async Task AddValueAsync(Stock stock)
{
_stock.TryAdd(stock.symbol, stock);
await Task.CompletedTask;
}
public Task<ICollection<Stock>> GetValues()
{
return Task.FromResult(_stock.Values);
}
}
My Hub is
I put the GetValues ​​method in while because I want data to come all the time.
public class MyHub : Hub
{
public readonly StockCaller _stock;
public MyHub(StockCaller stock)
{
_stock = stock;
}
public async Task SendRandomCharacter()
{
//TcpServer can be useable
while (true)
{
var result = await _stock.GetValues();
await Clients.All.SendAsync("receiveMessage", result);
}
}
}
I solved this problem by opening a new thread.
Like this.
public class StockCaller
{
public static ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();
public StockCaller()
{
Thread thread1 = new Thread(new ThreadStart(AddValue));
thread1.Start();
//AddValue();
}
public async void AddValue()
{
while (true)
{
string[] symbols = new string[6] { "USD", "EUR", "ATLAS", "GARAN", "ISBNK", "AKBNK" };
Random random = new Random();
foreach (var item in symbols)
{
Stock stock = new Stock()
{
symbol = item,
price = random.Next(100, 500),
percent = random.NextDouble(),
};
await AddValueAsync(stock);
}
}
}
public async Task AddValueAsync(Stock stock)
{
_stocks.TryAdd(stock.symbol, stock);
await Task.CompletedTask;
}
public async Task<ICollection<Stock>> GetValues()
{
return await Task.FromResult(_stocks.Values);
}
public void ClearStock()
{
_stocks.Clear();
}
}
StockHub is still same but i am sharing share
public class MyHub : Hub
{
public readonly StockCaller _stock;
public MyHub(StockCaller stock)
{
_stock = stock;
}
public async Task<IEnumerable<Stock>> SendRandomCharacter()
{
while (true)
{
var result = await _stock.GetValues();
await Clients.All.SendAsync("receiveMessage", result);
}
}
}

Xunit Testing an ActionResult

I am trying to write a unit test using Xunit and moq that will return a data from the client.GetAll().
At the moment when I debug the client.GetAll just return null.
This is my controller class
private readonly IClient _client;
public EventsController(IClient client)
{
_client = client;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<EventDTO>>> List()
{
var values = await _client.GetAll();
return Ok(values);
}
I am using my Client code implement. I am not sure if the IOptions is causing the issue
public class Client: IClient
{
public RestClient RestClient { get; set; }
public IOptions<MySettings>Settings { get; set; }
public Client(IOptions<MySettings>options)
{
Settings = options;
RestClient = new RestClient(options.Value.BaseUrl);
}
public async Task<List<EventDTO>> GetAll()
{
var request = new RestRequest(Settings.Value.GetAll, Method.GET);
var content = await RestClient.GetAsync<RootObject>(request);
var data = content.Events.SelectMany(con =>
con.Geometries.Select(geo =>
new EventDTO
{
Title = con.Title,
Id = con.Sources.FirstOrDefault()?.Id,
CategoriesTitle = con.Categories.FirstOrDefault()?.Title,
DateTime = geo.Date
})
).ToList();
return data;
}
This is my test class. I noticed that when i debug it does not go into the _client.GetAll() method.
Is this because I dont IOptionsoptions setup correctly?
public class EventsControllerTests
{
private readonly EventsController _controller;
private readonly Mock<IClient> _clientService;
public EventsControllerTests()
{
_clientService = new Mock<IClient>();
_controller = new EventsController(_clientService.Object)
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
}
};
}
[Fact]
public async Task Should_return_events_from_configured_service()
{
var response = new RootObject();
{
new Event()
{
Id = "sadsadsa"
};
};
var s = _clientService.Setup(x => x.Get(It.IsAny<string>())).ReturnsAsync(response);
var controllerResponse = await _controller.List();
var responseBody = controllerResponse.Value as IEnumerable<EventDTO>;
}
Thanks for the help.
You should test your GetAll method separately from the controller. In the controller you can just mock your client.
public class EventsControllerTests
{
private readonly Mock<IClient> _clientMock;
private readonly EventsController _testeeController;
public EventsControllerTests()
{
_clientMock = new Mock<IClient>();
_testeeController = new EventsController(_clientMock.Object);
}
[Fact]
public async Task ListTest()
{
var dtoList = new List<EventDto>{new EventDto(), new EventDto()};
_clientMock.Setup(c => c.GetAll()).ReturnsAsync(dtoList);
var response = await _testeeController.List();
var jsonResult = (JsonResult) response.Result;
var dtoListFromResponse = (IEnumerable<EventDto>) jsonResult.Value;
// compare dtoListFromResponse with dtoList
}
}

Unit Test using MS fakes: HttpClient and await

I have class which creates instance of HttpClient and call some method and returns response in async mode.
For ReadAsAsync, I have used nuget package "System.Net.Http.Formatting".
Source Code:
public class MyClass
{
readonly HttpClient client = new HttpClient();
public MyClass()
{
string myUrl = ConfigurationManager.AppSettings["MyWebAPI"];
client.BaseAddress = new Uri(myUrl);
}
public async Task<List<YourClass>> GetYourClass()
{
var filters = "string";
HttpResponseMessage response = await client.GetAsync(filters).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var notes = await response.Content.ReadAsAsync<List<YourClass>>();
return notes;
}
return null;
}
}
public class YourClass
{
private string Address { get; set; }
public YourClass(string address)
{
Address = address;
}
}
Unit Test:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
MyClass obj = new MyClass();
ShimHttpClient shimHttpClient = new ShimHttpClient();
ShimHttpClient.Constructor = (t) =>
{
shimHttpClient = new ShimHttpClient();
shimHttpClient.GetAsyncString = (a) =>
{
return new System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>(function1);
};
};
var returnVal = obj.GetYourClass();
}
}
private System.Net.Http.HttpResponseMessage function1()
{
return new System.Net.Http.HttpResponseMessage();
}
}
We can't change the source code. but need to unit test GetAsync and ReadAsAync call through dummy call test.
Declare that your test to run async and await the response from the source class
[TestMethod]
public async Task TestMethod1()
{
using (ShimsContext.Create())
{
MyClass obj = new MyClass();
ShimHttpClient shimHttpClient = new ShimHttpClient();
ShimHttpClient.Constructor = (t) =>
{
shimHttpClient = new ShimHttpClient();
await shimHttpClient.GetAsyncString = (a) =>
{
return new System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>(function1);
};
};
var returnVal = await obj.GetYourClass();
Assert.IsNotNull(returnVal);
//make more assertations on the returnVal
}
}

Categories