Specflow Integration test with HttpClient - c#

I'm trying to create some specflow tests and using a WebApplicationFactory and want to moq HttpClient calls with Moq.Contrib.HttpClient.
So when i call my client, it's not intiated well (doesn't match with the moq)
Any ideas?
Thanks
So i've 2 differents HttpClients
var httpMessageHandler1 = new Mock<HttpMessageHandler>();
httpMessageHandler1.SetupRequest(HttpMethod.Post, $"http://localhost/api/Method1");
var httpMessageHandler2 = new Mock<HttpMessageHandler>();
httpMessageHandler2
.SetupRequest(HttpMethod.Post, $"http://localhost/api/Method2")
.ReturnsResponse(JsonSerializer.Serialize(response), "application/json");
I inject them like this in the stepDefinition class :
var application = new WebFactory<Program>()
                .WithWebHostBuilder(builder =>
                {
                    builder.ConfigureServices(services =>
                    {
                        var serviceProvider = services.BuildServiceProvider();
                        services.AddMediatR(typeof(DeviceRequestModel));
                      services.AddHttpClient("Client1").ConfigurePrimaryHttpMessageHandler(() => httpMessageHandler1.Object);
                      services.AddHttpClient("Client2").ConfigurePrimaryHttpMessageHandler(() => httpMessageHandler2.Object);
                    });
              });
Here is my WebFactory :
internal class WebFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            base.ConfigureWebHost(builder);
            builder.UseEnvironment(Environments.Development);
            builder.UseTestServer()
                   .ConfigureTestServices(
                        services =>
                        {
                            services.AddScoped<TStartup>();
                            // Remove existing IHttpClientFactory and HttpClient
                            var httpClientFactoryDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(IHttpClientFactory));
                            services.Remove(httpClientFactoryDescriptor);
                            var httpClientDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(HttpClient));
                            services.Remove(httpClientDescriptor);
                        });
        }
    }
In my Command, i get the IHttpClientFactory
public Handler(IHttpClientFactory factory)
{
this.client = factory.CreateClient("Client1");
}
So when i do the
HttpResponseMessage response = await this.client.PostAsync
I've got this exception 'System.InvalidOperationException' dans System.Net.Http.dll and my client is not intiated well (doesn't match with the moq)
So it's not my moq object from services.AddHttpClient("Client1").ConfigurePrimaryHttpMessageHandler(() => httpMessageHandler1.Object);

Related

Add prefix "nameService" to all API Endpoints route, through swagger configuration

I have API Versionning swagger
namespace AccountingService
{
    public class Startup
    {
        //public Startup(IConfiguration configuration, IHostEnvironment env, ILogger<Startup> logger) { }
 
        //public void ConfigureServices(IServiceCollection services) { }
 
        public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider, IApiVersionDescriptionProvider provider)
        {
            if (HostEnvironment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
           
            UserHelper.InitDependencies(serviceProvider.GetRequiredService<IUserDataService>());
            app.ConfigureCustomMiddleware(Configuration, _appSettings);
            app.UseHttpsRedirection();
 
            app.UseRouting();
 
            app.UseAuthentication();
           
            app.UseUserService();
 
            if (_appSettings.Swagger.Enabled)
            {
                app.UseSwagger();
                app.UseSwaggerUI(options =>
                {
                    foreach (var description in provider.ApiVersionDescriptions)
                    {
                        options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToLowerInvariant());
                        options.RoutePrefix = $"{_appSettings.ServiceName}/swagger";
                    }
                });
            }
           
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
And there are a bunch of controllers with routing where the attributes of the controller are written like this
    [ApiVersion("1.0")]
    [Route("/api/v{version:apiVersion}/[controller]")]
    [ApiController]
    public class AccountCardController : CommonController
    {
       //CRUD methods
//BLL methods
//Utils methods
    }
And everything seems to be fine, but I need to add the name of the service itself to the routing of each methods
There is a solution for this, I have to register it manually for each controller, but this is wrong (I thought) and nonsense
Api route expect
Like that
add accounting-service everywhere at first and it will turn out like this
accounting-service/api/v{version:apiVersion}/[controller]
But I know for sure that this can be done somehow through the settings in the startup file, I don’t know the swagger settings so deeply to find them,
in google they say to do it through the endpoints.MapControllerRoute() method, but this is something not exactly what i need, it doesn’t help me
Swagger can't help. It produces a documentation of the available interfaces, but can't change the routing. While you could change the documentation through swagger by writing a SchemaProcessor or a DocumentProcessor, this would produce invalid URLs, that couldn't be processed by ASP core.
To solve this issue, you have to change your RouteAttribute on each controller class and apply the desired value.
[ApiVersion("1.0")]
// add desired value into route
[Route("accounting-service/api/v{version:apiVersion}/[controller]")]
[ApiController]
public class AccountCardController : CommonController
{
//CRUD methods
//BLL methods
//Utils methods
}
This is the cleanest approach by the given possibilities from ASP.core. Even if you have dozens of controllers that need to be changed, it will take you less then an hour to do so and if you would have to change hundreds of controllers you could think about a regular expression to run within "Find & Replace" to update all places.
Another approach would be to write your own middleware, that re-writes the incoming request before it is forwarded to ASP routing, but IMHO this is overkill in this case.

C# - Send a file in the body of an http request using RestRequest

I tried sending an xlsx file (from path) in the body of a POST http request.
I was able to send the file but it arrived as a corrupted file.(I have no way to try to check what's the issue on the api, because it's a api like Amazon etc.)
this is the code I tried:
public async Task<string> PostPostman()
    {
         try
            {
                string filePath = #"D:\example2.xlsx";
FileStream fs = File.OpenRead(filePath);
var streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/xlsx");
                var client = new RestClient("https://api.xxx.com/v1/FileUpload");
                var request = new RestRequest(Method.Post.ToString());
                request.Method = Method.Post;
                request.AddHeader("Content-Type", "application/xlsx");
                request.AddHeader("Authorization", "Bearer xxxxxxxxxxxxx");
                request.AddParameter("application/xlsx", streamContent.ReadAsStringAsync().Result, ParameterType.RequestBody);
                RestResponse response = client.Execute(request);
                Console.WriteLine(response.Content);
                return response.Content;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return ex.Message;
            }
        }
I found the issue was that ReadAsStringAsync() opened the file but didn't close it.
The solution I found is to send the file with File.ReadAllBytes(filePath) which reads the file and closes it back.
This is the final code:
public async Task<string> PostPostman()//found the code from the postman request I sent
        {
            try
            {
                string filePath = #"D:\example2.xlsx";
                var client = new RestClient("https://api.xxx.com/v1/FileUpload");
                var request = new RestRequest(Method.Post.ToString());
                request.Method = Method.Post;
                request.AddHeader("Content-Type", "application/xlsx");
                request.AddHeader("Authorization", "Bearer xxxxxxxxxxxxx");
                request.AddParameter("application/xlsx", File.ReadAllBytes(filePath), ParameterType.RequestBody);
                RestResponse response = client.Execute(request);
                Console.WriteLine(response.Content);
                return response.Content;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return ex.Message;
            }
        }

Unity Vector2.MoveTowards function is not working

Currently, I am making a board game with Unity. The player has to be moved according to the results of rolling dice, but the player always moves one space less in the first turn.
I checked that the dice was thrown well and the results were delivered well, but the player moves one space less, only in the first turn. (For example, assume that you throw the dice for the first turn and get 2, you don't move two spaces, but only one space.)
I put a script called FollowThePath in each player object (soju, beer, whiskey, cocktail), and decide player's order with the GameController.
In addition, waypoints were placed in each board game compartment managed in an array called waypoints. It is the principle of moving by stepping on each waypoint according to the result of throwing dice.
I'll attach the code.help me please.....
blue dots are waypoints. and the object on bottom right is the player.
FollowThePath.cs
private void Start()
    {
        transform.position = waypoints[wayPointIndex].transform.position;
        howManyMove = 0;
    }
    private void Update()
    {
        if (moveAllowed)
        {
            Move();
        }
    }
    private void Move()
    {
        if (wayPointIndex <= waypoints.Length - 1)
        {
           
            if (howManyMove < GameControl.yutSideThrown && transform.position == waypoints[wayPointIndex].transform.position)
            {
                isReallyMove = false;
               
                if (wayPointIndex == 5)
                    wayPointIndex += 15;
                else if (wayPointIndex == 10)
                    wayPointIndex += 15;
                else if (wayPointIndex == 22)
                    wayPointIndex += 6;
                else if (wayPointIndex == 27)
                    wayPointIndex -= 4;
                else if (wayPointIndex == 24)
                    wayPointIndex -= 9;
                else wayPointIndex += 1;
                //말을 실제로 몇번 움직였는지 나타내는 변수
                howManyMove += 1;
                
            }
            
            transform.position = Vector2.MoveTowards(transform.position, waypoints[wayPointIndex].transform.position, moveSpeed * Time.deltaTime);
            
            if (transform.position == waypoints[wayPointIndex].transform.position)
            {
               
                Debug.Log("Moved");
            }
            isReallyMove = true;
        
        }
    }
}
GameControl.cs
void Start()
    {   
        //각 player 변수에 object들 연결하는 코드
        player1 = GameObject.Find("soju");
        player2 = GameObject.Find("beer");
        player3 = GameObject.Find("whiskey");
        player4 = GameObject.Find("cocktail");
        //자기 차례에 moveAllowed가 true가 되어야함. 그래서 초기화는 false로
        player1.GetComponent<FollowThePath>().moveAllowed = false;
        player2.GetComponent<FollowThePath>().moveAllowed = false;
        player3.GetComponent<FollowThePath>().moveAllowed = false;
        player4.GetComponent<FollowThePath>().moveAllowed = false;
        whoWinsText.text = "";
        whosTurn.text = "소주 팀 차례!";
    }
    
    // Update is called once per frame
    void Update()
    {
        
        if(player1.GetComponent<FollowThePath>().howManyMove >= yutSideThrown && player1.GetComponent<FollowThePath>().isReallyMove)
        {
            whosTurn.text = "맥주 팀 차례!";
            player1.GetComponent<FollowThePath>().howManyMove = 0;
            player1.GetComponent<FollowThePath>().moveAllowed = false;
        }
...
please help me!TT

Dapper QueryMultiple Get the actual values from the DB

The dataset return 4 data tables as resultset but all in object{string} type even though in the table it is of different data types like int.
var ds = new DataSet();
        return  var ds = WithConnection(c =>
            {
                var multi = c.QueryMultiple(sql: "StoredProcedureName",
                                             param: new { Project = projectID },
                                            commandType: CommandType.StoredProcedure);
                while (!multi.IsConsumed)
                {
                    var dt = ChngDataTable(multi.Read());
                    ds.Tables.Add(dt);
                }
                return ds;
            });
protected DataTable ChngDataTable(IEnumerable<dynamic> items)
        {
            var exisData= items.ToArray();
            var dt = new DataTable();
            if (exisData.Count() == 0) return dt;
               
            foreach (var key in ((IDictionary<string, object>)data[0]).Keys)
            {
              if(!dt.Columns.Contains(key))
 dt.Columns.Add(key);
            }
            foreach (var d in exisData)
            {
                dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
            }
            return dt;
        }`
           
Is there any easy way to get the values with the actual data type from the DB as I cannot use any properties
Please help!!!!
please, take a look on the https://dapper-tutorial.net/querymultiple example.
You can use parameterised version of the Read method in order to get the type of choice.
If I understand the idea correctly, you would like to get data in the form of DataTables, then change DataTables and then do something with them.
In this case I'd split the work into stages in order to benefit from statically typed C# language.
1) Retrieve a result from database
2) Map to the POCO objects (like it is done in the example above)
3) Change fields according to a business logic
4) Map objects back to DataTables (either custom code with Reflection or any nuget package of choice).

How I can order by descending and then take some items using linq?

I have the following C# LINQ code :
List<myProductList> qMain = (
from m in db.ProductsList.OrderByDescending
(it => it.GroupCode == 1 || it.L1 == 1)
where m.GoodCode == 1 || m.L1 == 1
select new myProductList
{
StackAmount = m.StackAmount,
GoodCode = m.GoodCode,
PrivateCodeForSort = m.PrivateCodeForSort,
GoodMainCode = m.GoodMainCode,
MaxSellPrice = m.MaxSellPrice,
SellPrice5 = m.SellPrice5,
SellPriceType = m.SellPriceType,
GoodExplain1 = m.GoodExplain1,
Writer = m.Writer,
DragoMan = m.DragoMan,
GoodName = m.GoodName,
Printing = m.Printing,
CoverType = m.CoverType,
PrintYear = m.PrintYear,
PrintPeriod = m.PrintPeriod,
Creation = m.CreationDate
}).Take(50).ToList();
I have a kind of serious problem, The ProductList table is a very big and I don't want to transfer all rows from my database server so I solve this problem by taking 50 rows which is my necessary but the problem is I want to order by descending first of all and then take 50 rows but this code first take 50 rows by ascending and then order by decending only those 50 rows that has already transferred and sorted. how I can fix this ?
No, the code you've given:
Orders the results
Filters the results
Projects the results
Limits the results to 50
... in that order.
On the other hand, it's a slightly odd OrderByDescending call to start with. If you want a different ordering applied as well you could easily do that too - for example:
from m in db.ProductsList
orderby (it.GroupCode == 1 || it.L1 == 1) descending, it.SellPrice5 descending
where m.GoodCode == 1 || m.L1 == 1
select new myProductList
... // code as before
Something like this:
List<myProductList> qMain = (
                         from m in db.ProductsList.OrderByDescending(it => it.GroupCode == 1 || it.L1 == 1)
                         where m.GoodCode == 1 || m.L1 == 1                                                                                            
                         select new myProductList
                         {
                             StackAmount = m.StackAmount,
                             GoodCode = m.GoodCode,
                             PrivateCodeForSort = m.PrivateCodeForSort,
                             GoodMainCode = m.GoodMainCode,
                             MaxSellPrice = m.MaxSellPrice,
                             SellPrice5 = m.SellPrice5,
                             SellPriceType = m.SellPriceType,
                             GoodExplain1 = m.GoodExplain1,
                             Writer = m.Writer,
                             DragoMan = m.DragoMan,
                             GoodName = m.GoodName,
                             Printing = m.Printing,
                             CoverType = m.CoverType,
                             PrintYear = m.PrintYear,
                             PrintPeriod = m.PrintPeriod,
                             Creation = m.CreationDate
                         }).OrderByDescending(m=>m.GoodName).Take(50).ToList();
It won't bring the entire dataset; you can look at the generated SQL query to confirm.

Categories

Resources