I am trying to implement an Assert over my function which is called in separate project. The function called is as follows:
public async Task<List<DynamicTableEntity>> PopulateTable(
string documentId,
IEnumerable<string> lines,
JsonSchema schema,
string type,
string subType,
string format,
bool upsert ){var tableEntries = new List<DynamicTableEntity>( tableData.Count );
.....
return tableEntries; }
In Some cases it will throw an exception and I would like to test that using Xunit framework. My TDD code is like this:
public async Task UploadAndSchemaCheckOnMissingKey()
{
var table = await _tableStore.PopulateTable(null, lines, schema, "tableOutput", null, "test", false);
await Assert.ThrowsAsync<ArgumentException>(table);
}
I get the error as cannot convert System.Collection.generic.List<table.DynamicEntity> to System.Func<System.Threading.tasks.task>.
How should I handle this that My test case pass when the exception is thrown?
You can use it something like this:
Func<Task> table = async() => await _tableStore.PopulateTable(null, lines, schema, "tableOutput", null, "test", false);
var ex = await Assert.ThrowsAsync<FormatException>(table);
Assert.Contains("expected error message", ex.Message);
Related
I am new to Xunit. I throw a new exception in my code :
throw new NotImplementedException("Missing UPC. File is corrupt");
in my test file I wrote:
[Fact]
public void ParserRow_Throws_Exception_For_Null_UPC()
{
var record = GetRessoRecord();
record.UPC = "";
RevenueReportItem result = Sut.ParseRow(record);
Assert.Throws<NotImplementedException>(() => Sut.ParseRow(record));
}
The error message in the Test Explorer says
System.NotImplementedException : Missing UPC. File is corrupt
How do I add in the returned quote?
The synchronous variant of Throws<> is now obsolete.
You're calling the tested method twice. Remove the first call that's outside of the assert, as it will throw the exception and halt test execution.
The call to Throws<> returns the exception object, from which you can retrieve and check the message, like so:
[Fact]
public async Task ParserRow_Throws_Exception_For_Null_UPC()
{
var exceptionDetails = await Assert.ThrowsAsync<NotImplementedException>(() => {
throw new NotImplementedException("foo");
});
Assert.Equal("foo", exceptionDetails.Message);
}
I am using neo4jclient graph database with .net core API. I have to add the health checks. I have created my own health check using Ihealthcheck interface. below is my healthcheck class
public class DatabaseHealthCheck : IHealthCheck
{
public DatabaseHealthCheck(IGraphClient graphClient)
{
_graphClient = graphClient;
}
private readonly IGraphClient _graphClient;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
try
{
var result = await _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<DatabaseDetail>()).ResultsAsync;
foreach (var res in result)
{
if (res.currentStatus == "Online")
{
return await Task.FromResult(
HealthCheckResult.Healthy("Healthy"));
}
}
}
catch (Exception ex)
{
return new HealthCheckResult(status: context.Registration.FailureStatus, exception: ex);
}
return HealthCheckResult.Healthy();
// return await Task.FromResult(
// new HealthCheckResult(context.Registration.FailureStatus,
// "Unhealthy"));
}
}
With this health check I want to get the database details and then check the status of database weather it is online or not but I am getting the below error
Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied.
Can anyone help me ?
The query you're writing will not return anything, what you're actually executing is:
MATCH (show databases)
RETURN n
You can see this if you change your code to look like this:
var query = _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<string>());
var text = query.Query.DebugQueryText;
var result = await query.ResultsAsync;
If you put a breakpoint in so you can see what the text variable will be you'll be able to see it.
Now! I can't think how to get what you want when you're using the GraphClient - it might be possible with the BoltGraphClient - but the error you're getting implies you're using the former.
IF you were on the BoltGraphClient, you could access the Driver and execute:
var session = ((BoltGraphClient)_graphClient).Driver.AsyncSession(d => d.WithDatabase("system"));
var cursor = await session.RunAsync("SHOW DATABASES");
while (await cursor.FetchAsync())
{
var name = cursor.Current.Values["name"].As<string>();
var status = cursor.Current.Values["currentStatus"].As<string>();
Console.WriteLine($"{name} is {status.ToUpperInvariant()}");
}
I don't know any other work around with the http GraphClient - it would need to be added to the client. In theory - it's not a complex PR to do if you wanted to.
I am looking for a way to add manual raw SQL call to standard AppDbContext interaction. Say I have following code:
Message m = new Message
{
Title = message.Title,
Body = message.Body,
Date = DateTime.Now,
Foo = "foo"
};
_context.Messages.Add(m);
// Add some manual UPDATE SQL here, like:
// UPDATE SomeOtherTable SET Foo = 'Something' WHERE SomeComplex = 'Condition'
_context.SaveChanges();
The most important thing is to make that manual SQL part of command / transaction that gets created and executed as part of SaveChanges. If there is a way to inject my modification into SQL generated by SaveChanges - that's what I'm looking for.
I use an overload for SaveChangesAsync on my DbContext base that accepts any arbitrary raw sql, the key is to wrap all the processing within a manually created transaction:
public async Task<int> SaveChangesAsync(string customCommand,
CancellationToken cancellationToken = default(CancellationToken),
params object[] parameters)
{
using (var transaction = Database.BeginTransaction())
{
try
{
var result = await base.SaveChangesAsync(true, cancellationToken);
await Database.ExecuteSqlCommandAsync(customCommand, parameters);
transaction.Commit();
return result;
}
catch (Exception ex)
{
transaction.Rollback();
throw ex.Handle();
}
}
}
Note:
Handle() is an extension method where I transform the t-sql exceptions into my business exceptions, so that method is not relevant here.
I am using DeleteDocumentAsync as per below code.
public static void DeleteErrorLog(List<string> LogID, string collectionName)
{
FeedOptions queryOptions = new FeedOptions { EnableCrossPartitionQuery = true };
try
{
//getting resource id for a document with given logid
var db = client.CreateDatabaseQuery().Where(x => x.Id == databaseName).ToList().First();
var coll = client.CreateDocumentCollectionQuery(db.SelfLink).Where(x => x.Id == collectionName).ToList().First();
var docs = client.CreateDocumentQuery(coll.SelfLink, queryOptions).Where(x => x.Id == LogID[0]).AsEnumerable().Single();
var collectionUri = UriFactory.CreateDocumentUri(databaseName, collectionName, docs.ResourceId);
client.DeleteDocumentAsync(collectionUri);
}
catch (Exception) { throw; }
}
Every value is populating correctly and I am getting the document that I need to delete still unable to delete it? Any help is greatly appreciated
You are probably missing the PartitionKey for the delete operation:
var documentUri = UriFactory.CreateDocumentUri(databaseName, collectionName, LogID[0]);
client.DeleteDocumentAsync(documentUri, new RequestOptions(){PartitionKey=new PartitionKey(LogID[0])}).GetAwaiter().GetResult();
Also, if you already know the Id, which in your case is LogID[0], you don't need the Query.
You're not awaiting client.DeleteDocumentAsync, which means your catch will not catch exceptions that occur in the Task that's created - it will silently fail.
My guess is that due to this, there is an exception being thrown in DeleteDocumentAsync that's not subsequently caught where expected.
Ideally, this method would be re-written to use async/await, then your try catch will pick up any exceptions being thrown:
public static async Task DeleteErrorLog(List<string> LogID, string collectionName)
{
...
await client.DeleteDocumentAsync(collectionUri);
...
}
You'll have to make sure that the code calling this method also uses await.
I have the following Log method (for a Unit Test project):
public static void WriteLogFile<T>(T obj, [System.Runtime.CompilerServices.CallerMemberName] string callingMethod = "")
{
#if WRITELOGFILE
var path = Path.Combine(LogFileLocation, callingMethod + ".json");
var content = (typeof(T) == typeof(string)) ? (obj as string) : JsonConvert.SerializeObject(obj);
File.WriteAllText(path, content);
#endif
}
And I use it in the following TestMethod:
[TestMethod]
public async Task TestGetUserInfoAsync()
{
//var tokenFile = TestUtils.GetLogFileLocation(nameof(this.TestRedeemTokensAsync2));
var tokenFile = #"D:\Temp\TestLog\TestRedeemTokensAsync2.json";
var accessToken = JsonConvert.DeserializeObject<dynamic>(File.ReadAllText(tokenFile))
.access_token.ToString();
var result = await GoogleService.GetUserInfoAsync(this.systemConfig,
accessToken);
TestUtils.WriteLogFile(result);
Assert.IsNotNull(result);
}
I have other 3 Test Methods and they all runs correctly, and they all have async/await Tasks, writing log files with the filenames taken from the method names.
However, for the above specific method, the parameter callingMethod is an empty string (not null). The result file is a file named .json (it is a valid file in Windows). I am not sure if this is related to Unit Test project only.
Why is it happening? How can I debug in this case?
Additional information: I thought it may be because I added the following method, and the 1st calling mess up:
public static string GetLogFileLocation([System.Runtime.CompilerServices.CallerMemberName] string callingMethod = "")
{
var path = Path.Combine(LogFileLocation, callingMethod + ".json");
return path;
}
However, I tried removing it and use hard string for file path (as you see in my code above) instead, but the problem persist.
EDIT: I added the Stack Trace that may be useful. I notice there is a [External Code] row between the code. I don't know what causes it.
EDIT2: The IL code indeed has problem: the 4 (sorry, 4, not 3) other TestMethods are running fine, and their IL code is correct, like this:
However, the method I am having problem with, I don't see any function call. The only WriteLogFile I can see is this one, but it is a string:
Full IL code here: http://pasted.co/cf4b0ea7
The problem seems to be happening with async and dynamic going together. Remove either one (switch to synchronous or casting into a strongly typed variable) fix the problem:
[TestMethod]
public async Task TestGetUserInfoAsync()
{
//var tokenFile = TestUtils.GetLogFileLocation(nameof(this.TestRedeemTokensAsync2));
var tokenFile = #"D:\Temp\TestLog\TestRedeemTokensAsync2.json";
var accessToken = (JsonConvert.DeserializeObject<dynamic>(File.ReadAllText(tokenFile))
.access_token.ToString()) as string; // Here, cast this to string instead of keeping it as dynamic
var result = await GoogleService.GetUserInfoAsync(this.systemConfig,
accessToken);
TestUtils.WriteLogFile(result);
Assert.IsNotNull(result);
}