I have a test in which I am trying to collect an activity/span in memory using the In-Memory exporter. But the test fails with exception that says the collection is empty.
I have tried adding delay before assertion but result is still the same. Is anything more required in the setup so it starts capturing the activities?
[Fact]
public void Can_collect_Activities_in_memory()
{
var serviceName = "ServiceName";
var activities = new List<Activity>();
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(serviceName)
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("in-memory"))
.AddInMemoryExporter(activities)
.Build();
var source = new ActivitySource(serviceName);
var activity = source.StartActivity("TestActivity");
Assert.Single(activities);
}
Related
I am trying to write my very first xunit test with Database, instead of mocking the DbContext I used the inMemoryDatabase as I read in articles, so I did like following
public class GetCustomersTest
{
DbContextOptions _context;
public GetCustomersTest()
{
if (_context==null)
_context = CreateContextForCustomer();
}
[Theory]
[InlineData(1)]
[InlineData(2)]
public void GetCustomerById_ShouldReturnCorrectObject(int id)
{
using (var context = new DataBaseContext(_context))
{
var customerByIdService = new GetCustomerByIdService(context);
var customer = customerByIdService.Execute(id);
var customerActual = context.Customers.Where(x => x.Id == id).SingleOrDefault();
var customerTmp = new Customer()
{
Id = id,
FirstName = customer.Data.FirstName,
LastName = customer.Data.LastName,
Phone = customer.Data.Phone,
ClientNote = customer.Data.ClientNote
};
Assert.Equal(customerTmp.FirstName, customerActual.FirstName);
Assert.Equal(customerTmp.LastName, customerActual.LastName);
Assert.Equal(customerTmp.Phone, customerActual.Phone);
Assert.Equal(customerTmp.ClientNote, customerActual.ClientNote);
}
}
private DbContextOptions<DataBaseContext> CreateContextForCustomer() {
var options = new DbContextOptionsBuilder<DataBaseContext>()
.UseInMemoryDatabase(databaseName: "SalonDatabase")
.Options;
using (var context = new DataBaseContext(options))
{
context.Customers.Add(new Customer
{
Id = 1,
FirstName = "User1",
LastName = "Surname1",
Phone = "123",
ClientNote = ""
});
context.Customers.Add(new Customer
{
Id = 2,
FirstName = "User2",
LastName = "Surname2",
Phone = "4567",
ClientNote = "The best"
});
context.SaveChanges();
}
return options;
}
}
it works find on [InlineData(1)] but when it comes to [InlineData(2)], it seems that it starts to run the constructor again , so as it wants to add the customerdata to table, it says that the record with that Id key exists.what is the best way for doing that?
When building your DB context options, add a GUID to the database name to make it unique:
var options = new DbContextOptionsBuilder<DataBaseContext>()
.UseInMemoryDatabase(databaseName: "SalonDatabase" + Guid.NewGuid().ToString())
.Options;
Or if you're using a new enough language version you can use string interpolation instead of concatenation:
var options = new DbContextOptionsBuilder<DataBaseContext>()
.UseInMemoryDatabase(databaseName: $"SalonDatabase{Guid.NewGuid()}")
.Options;
If you do this then every test uses a brand new database, unaffected by any previous tests.
As #MicheleMassari says, it's good practice to follow the Arrange Act Assert pattern, so that it's clear which lines are setting things up ready for the test and which are performing the action that you want to test the outcome of.
Arrange inputs and targets. Arrange steps should set up the test case. Does the test require any objects or special settings? Does it need to prep a database? Does it need to log into a web app? Handle all of these operations at the start of the test.
Act on the target behavior. Act steps should cover the main thing to be tested. This could be calling a function or method, calling a REST API, or interacting with a web page. Keep actions focused on the target behavior.
Assert expected outcomes. Act steps should elicit some sort of response. Assert steps verify the goodness or badness of that response. Sometimes, assertions are as simple as checking numeric or string values. Other times, they may require checking multiple facets of a system. Assertions will ultimately determine if the test passes or fails.
The code samples in that page are written in Python rather than C#, but the pattern is valid for unit tests in any language. In the case of your test, structuring the test in this way makes it clear whether you're testing the behaviour of GetCustomerByIdService.Execute or of Entity Framework's Where method.
I'm using the InMemory database to test my repository layer in my ASP .NET Core Web API application.
Thus I have an issue, in several tests, I setup data. But, with the same code, when I run the tests sometimes the data is present and sometimes it is not. I don't understand why.
I'm using XUnit Testing Framework.
Here is my test :
public class UserRepositoryTest
{
private ApplicationDbContext context;
void setup()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "ApplicationDatabase")
.Options;
this.context = new ApplicationDbContext(options);
this.context.Database.EnsureDeleted();
}
[Fact]
void GetUserByUsernameTest()
{
this.setup();
// Given
var manager = new User {Username = "Ombrelin", Email = "test#test.fr"};
context.Users.Add(manager);
context.SaveChanges();
// When
var repo = new UserRepository(context);
var user = repo.GetUserByUsername("Ombrelin");
// Then
Assert.Equal("Ombrelin", user.Username);
}
[Fact]
void FindUsersByUsernameContainsTest()
{
this.setup();
// Given
var manager1 = new User {Username = "Arsène", Email = "test#test.fr"};
var manager2 = new User {Username = "Jean Michel", Email = "test#test.fr"};
context.Users.Add(manager1);
context.Users.Add(manager2);
context.SaveChanges();
// When
var repo = new UserRepository(context);
var users = repo.findUsersByUsernameContains("Ars");
// Then
Assert.Single(users);
}
Does anyone have a clue about this ?
Thanks in advance,
You are reusing the same database context across multiple tests. Tests may run in parallel. Thus, when using the same database context tests may influence each other's outcome. To avoid this, you need to isolate the tests by letting them use a clean database context:
public class UserRepositoryTest
{
[Fact]
public void GetUserByUsernameTest()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: $"ApplicationDatabase{Guid.NewGuid()}")
.Options;
using(var context = new ApplicationDbContext(options))
{
// Given
var manager = new User { Username = "Ombrelin", Email = "test#test.fr" };
context.Users.Add(manager);
context.SaveChanges();
// When
var repo = new UserRepository(context);
var user = repo.GetUserByUsername("Ombrelin");
// Then
Assert.Equal("Ombrelin", user.Username);
}
}
}
By appending a unique id to the database name, you are ensuring, that tests are using a unique in-memory database. Obviously, this will make test execution slower. A lot of testers also use different contexts for seeding the data and performing the test:
public class UserRepositoryTest
{
[Fact]
public void GetUserByUsernameTestSeparateContexts()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: $"ApplicationDatabase{Guid.NewGuid()}")
.Options;
using (var context = new ApplicationDbContext(options))
{
// Given
var manager = new User { Username = "Ombrelin", Email = "test#test.fr" };
context.Users.Add(manager);
context.SaveChanges();
}
using (var context = new ApplicationDbContext(options))
{
// When
var repo = new UserRepository(context);
var user = repo.GetUserByUsername("Ombrelin");
// Then
Assert.Equal("Ombrelin", user.Username);
}
}
}
This makes the tests more realistic, since functions, that are seeding the data, and functions, that are using the data, often use different contexts. Also keep in mind, that the InMemoryProvider is not a relational database. Therefore, it does not support some features of actual database servers such as referential integrity checks, TimeStamp, IsRowVersion and others. Check the MS documentation for details: here.
Below is the code I am trying to use to append all tests to a single report. However, latest test is replacing all the older test reports. So, it's not appending to a single report for some reason. Can you please help me out here?
var htmlReporter = new ExtentHtmlReporter(ResourcesConfig.ReportPath);
extent = new ExtentReports();
extent.AttachReporter(htmlReporter);
htmlReporter.LoadConfig(ResourcesConfig.ReportXMLPath);
**htmlReporter.AppendExisting = true;**
I had a lot of trouble with this as well as the documentation doesn't explain much. I have one method called ReportCreation which runs for every test case and in that method i have the following:
public static ExtentReports ReportCreation(){
System.out.println(extent);
if (extent == null) {
extent = new ExtentReports();
htmlReports = new ExtentHtmlReporter(fileName+ n + "\\extentReportFile.html");
htmlReports.config().setReportName("Pre release Smoke test");
htmlReports.config().setTheme(Theme.STANDARD);
htmlReports.config().setTestViewChartLocation(ChartLocation.BOTTOM);
extent.attachReporter(htmlReports);
}
else {
htmlReports = new ExtentHtmlReporter(fileName+ n+ "\\extentReportFile.html");
htmlReports.setAppendExisting(true);
extent.attachReporter(htmlReports);
}
return extent;
}
So when the first unit test is run, it will create the html report, but the second unit test will see that the report has already been generated and so use the existing one.
I have created a random number generator so that it goes to a different report on every run
public static Random rand = new Random();
public static int n = rand.nextInt(10000)+1;
I was facing the same issue. My solution was using .NET Core so ExtentReports 3 and 4 were not supported.
Instead, I wrote code to merge the results from previous html file to the new html file.
This is the code I used:
public static void GenerateReport()
{
// Publish test results to extentnew.html file
extent.Flush();
if (!File.Exists(extentConsolidated))
{
// Rename extentnew.html to extentconsolidated.html after execution of 1st batch
File.Move(extentLatest, extentConsolidated);
}
else
{
// Append test results to extentconsolidated.html from 2nd batch onwards
_ = AppendExtentHtml();
}
}
public static async Task AppendExtentHtml()
{
var htmlconsolidated = File.ReadAllText(extentConsolidated);
var htmlnew = File.ReadAllText(extentLatest);
var config = Configuration.Default;
var context = BrowsingContext.New(config);
var newdoc = await context.OpenAsync(req => req.Content(htmlnew));
var newlis = newdoc.QuerySelector(#"ul.test-list-item");
var consolidateddoc = await context.OpenAsync(req => req.Content(htmlconsolidated));
var consolidatedlis = consolidateddoc.QuerySelector(#"ul.test-list-item");
foreach (var li in newlis.Children)
{
li.RemoveFromParent();
consolidatedlis.AppendElement(li);
}
File.WriteAllText(extentConsolidated, consolidateddoc.DocumentElement.OuterHtml);
}
This logic bypasses any Extent Report reference and treats the result file as any other html.
Hope this helps.
Long story short, I'm using GeneticSharp for an iterative/conditional reinforcement learning algorithm. This means that I'm making a bunch of different GeneticAlgorithm instances, each using a shared SmartThreadPool. Only one GA is running at a time though.
After a few iterations of my algorithm, I run into this error, which happens when attempting to start the SmartThreadPool.
Is there any obvious reason this should be happening? I've tried using a different STPE and disposing of it each time, but that didn't seem to help either. Is there some manual cleanup I need to be doing in between each GA run? Should I be using one shared GA instance?
Edit: Quick code sample
static readonly SmartThreadPoolTaskExecutor Executor = new SmartThreadPoolTaskExecutor() { MinThreads = 2, MaxThreads = 8 };
public static void Main(string[] args)
{
var achromosome = new AChromosome();
var bchromosome = new BChromosome();
while(true)
{
achromosome = FindBestAChromosome(bchromosome);
bchromosome = FindBestBChromosome(achromosome);
// Log results;
}
}
public static AChromosome FindBestAChromosome(BChromosome chromosome)
{
AChromosome result;
var selection = new EliteSelection();
var crossover = new UniformCrossover();
var mutation = new UniformMutation(true);
using (var fitness = new AChromosomeFitness(chromosome))
{
var population = new Population(50, 70, chromosome);
var ga = new GeneticAlgorithm(population, fitness, selection, crossover, mutation);
ga.Termination = new GenerationNumberTermination(100);
ga.GenerationRan += LogGeneration;
ga.TaskExecutor = Executor;
ga.Start();
LogResults();
result = ga.BestChromosome as AChromosome;
ga.GenerationRan -= LogGeneration;
}
return result;
}
public static BChromosome FindBestBChromosome(AChromosome chromosome)
{
BChromosome result;
var selection = new EliteSelection();
var crossover = new UniformCrossover();
var mutation = new UniformMutation(true);
using (var fitness = new BChromosomeFitness(chromosome))
{
var population = new Population(50, 70, chromosome);
var ga = new GeneticAlgorithm(population, fitness, selection, crossover, mutation);
ga.Termination = new GenerationNumberTermination(100);
ga.GenerationRan += LogGeneration;
ga.TaskExecutor = Executor;
ga.Start();
LogResults();
result = ga.BestChromosome as BChromosome;
ga.GenerationRan -= LogGeneration;
}
return result;
}
AChromosome and BChromosome are each fairly simple, a couple doubles and ints and maybe a function pointer (to a static function).
Edit2: Full call stack with replaced bottom two entries
Unhandled Exception: System.IO.IOException: Insufficient system resources exist to complete the requested service.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.Threading.EventWaitHandle..ctor(Boolean initialState, eventResetMode mode, string name)
at Amib.Threading.SmartThreadPool..ctor()
at GeneticSharp.Infrastructure.Threading.SmartThreadPoolTaskExecutor.Start()
at GeneticSharp.Domain.GeneticAlgorithm.EvaluateFitness()
at GeneticSharp.Domain.GeneticAlgorithm.EndCurrentGeneration()
at GeneticSharp.Domain.GeneticAlgorithm.EvolveOneGeneration()
at GeneticSharp.Domain.GeneticAlgorithm.Resume()
at GeneticSharp.Domain.GeneticAlgorithm.Start()
at MyProject.Program.FindBestAChromosome(BChromosome chromosome)
at MyProject.Program.Main(String[] args)
Edit3: One last thing to note is that my fitness functions are pretty processing-intensive and one run can take almost 2g of ram (running on a machine with 16g, so no worries there). I've seen no problems with garbage collection though.
So far, this only happens after about 5 iterations (which takes multiple hours).
It turns out it was my antivirus preventing the threads from finalizing. Now I'm running it on a machine with a different antivirus and it's running just fine. If I come up with a better answer for how to handle this in the future, I'll update here.
I have unit test for a ServiceStack based service that passes on my windows workstation, however the TeamCity server which is on ubuntu/mono doesn't pass - other tests do run however, just one in particular.
This fails
[Test]
public void Post_Valid_Property_Should_Return_HttpStatus_OK()
{
var manager = new Mock<IRedisClientsManager>();
var redisClient = new Mock<IRedisClient>();
var redisTypedClient = new Mock<IRedisTypedClient<Share.Property.Model.Property>>();
manager.Setup(t => t.GetClient()).Returns(redisClient.Object);
redisClient.Setup(t => t.As<Share.Property.Model.Property>()).Returns(redisTypedClient.Object);
var sut = new SomeService(manager.Object);
var result = sut.Post(new PropertySaveRequest {Property = new Share.Property.Model.Property { Id = 1, OwnerId = 2 } });
Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
Other tests not using mocks pass fine eg.
[Test]
public void Post_Invalid_Property_Should_Throw_Exception()
{
_container = new WindsorContainer()
.Install(new PropertyInstaller());
var service = _container.Resolve<IPropertyService>();
Assert.That(() => service.Post(new PropertySaveRequest { Property = new Share.Property.Model.Property{Id=-11, OwnerId = -14} }),
Throws.Exception.TypeOf<ArgumentOutOfRangeException>());
}
TeamCity log
My guess is the error is Moq related, as the other test can use Castle IOC without throwing.
Test(s) failed. System.Collections.Generic.KeyNotFoundException : The given key was not present in the dictionary.
Any ideas appreciated