AEM Mocks: Cannot Inject Config - unit-testing

I am using AEM Mocks to test a custom servlet that uses a configuration, as such:
#Activate
void activate(final Config config) { ... }
I am following the approach described here and here to register and inject the service together with a HashMap, as such:
private static Map<String, Object> myHashMap = new HashMap<>();
...
myHashMap.put("a", "b");
myHashMap.put("c", "d");
...
servlet = context.registerInjectActivateService(new MyServlet(), myHashMap);
However, this approach doesn't work. The config object passed above, inside the activate function, is corrupted. For every key-value pair above, it sets null as the value. So instead of:
a -> b
c -> d
It sets:
a -> null
c -> null
Inside the HashMap. Can anyone please help? Thanks!
P.S. I should add that I am using version 2.3.0 of AEM Mocks since the recent versions cause an issue with an older artifact. For more info on that, see here.

I tested it, and it works with version 2.3.0 too. Could you check the following example? After that, it is probably a maven issue. Then we would need more information.
Here is my test servlet:
#Component(service = Servlet.class,
property = {
SLING_SERVLET_PATHS + "=/bin/servlet/test",
SLING_SERVLET_METHODS + "=GET",
SLING_SERVLET_EXTENSIONS + "=text"
})
#Designate(ocd = TestServlet.Config.class)
public class TestServlet extends SlingSafeMethodsServlet {
#ObjectClassDefinition
public #interface Config {
#AttributeDefinition(
name = "Name",
description = "Name used in the hello world text"
)
String name() default "Alex";
#AttributeDefinition(
name = "Greeting",
description = "Greeting - Morning, to demonstrate the dot-replacement"
)
String greeting_morning() default "Good Morning";
}
private Config config;
#Override
protected void doGet(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println(this.getGreeting());
}
public String getGreeting() {
return config.greeting_morning() + ", " + config.name();
}
#Activate
void activate(final Config config) {
this.config = config;
}
}
Here is a JUnit 4 test:
public class TestServletTest {
#Rule
public final AemContext context = new AemContext();
#Test
public void testWithoutConfig() {
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet());
assertEquals("Good Morning, Alex", testServlet.getGreeting());
}
#Test
public void testWithConfig() {
final Map<String, Object> properties = new HashMap<>();
properties.put("name", "Berndt");
properties.put("greeting.morning", "Keep sleeping");
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet(), properties);
assertEquals("Keep sleeping, Berndt", testServlet.getGreeting());
}
}

Related

asp.net core 6.0 web api unit test using NUnit

I am trying to create the simple web api test for the controller action method I have in my project. I already create and add the test project in my solution. And add the Nunit nuget package in test project.
The controller I am trying to test is look like this:
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly IHostEnvironment _hostEnvironment;
private readonly ILogger<HomeController> _logger;
private BaseDataAccess _datatAccess = new BaseDataAccess()
public HomeController(ILogger<HomeController> logger, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
_logger = logger;
_configuration = configuration;
_hostEnvironment = hostEnvironment;
}
[HttpGet("GetInfo/{code}")]
public IActionResult GetInfo(string code)
{
List<InfoModel> infos = new List<InfoModel>();
int isNumber;
if (String.IsNullOrEmpty(code) || !int.TryParse(code, out isNumber))
{
_logger.LogInformation(String.Format("The code pass as arguments to api is : {0}", code));
return BadRequest("Invalid code");
}
try
{
_logger.LogDebug(1, "The code passed is" + code);
SqlConnection connection = _datatAccess.GetConnection(_configuration, _hostEnvironment);
string sql = string.Format ("SELECT * from table1 where code={0}", code);
DataTable dt = _datatAccess.ExecuteQuery(connection,CommandType.Text, sql);
if (dt != null && dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
infos.Add(new InfoModel
{
ID = dr["id"].ToString(),
code = dr["code"].ToString()
});
}
}
}
catch (Exception ex)
{
_logger.LogError(4, String.Format("Error Message: " + ex.Message + "\n" + ex.StackTrace));
return BadRequest("There is something wrong.Please contact the administration.");
}
return new OkObjectResult(infos);
}
}
Now when I try to create the unit test I need to pass the configuration, hostenvironment and logger to HomeController from my TestHomeController. And I don't know how to instantiate these settings and pass to controller:
using NUnit.Framework;
using Microsoft.AspNetCore.Mvc;
using MyApi.Models;
using MyApi.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace MyApi.Tests
{
[TestFixture]
public class TestHomeController: ControllerBase
{
private readonly IConfiguration _configuration; //How to instantiate this so it is not null
private readonly IHostEnvironment _hostEnvironment ;//How to instantiate this so it is not null
private ILogger<HomeController> _logger;//How to instantiate this so it is not null
[Test]
public void GetInfo_ShouldReturnAllInfo()
{
var controller = new HomeConteoller(_logger, _configuration, _hostEnvironment);
var result = controller.GetInfo("11");
var okObjectResult = (OkObjectResult)result;
//Assert
okObjectResult.StatusCode.Equals(200);
}
}
}
Thanks for any help and suggestions.
Probably, you have startup.cs. Don't you?
if you gonna test a controller, then you need to build a whole instance of an application. Here I put an example of how you can test your code if you have Startup.cs.
public class SUTFactory : WebApplicationFactory<Startup>
{
protected override IHostBuilder CreateHostBuilder()
{
return Program.CreateHostBuilder(null);
}
}
public class TestControllerTests
{
private SUTFactory factory;
private HttpClient _client;
public TestControllerTests()
{
factory = new SUTFactory();
_client = factory.CreateClient();
}
[Test]
public async Task GetPatientInterviewID_ShouldReturnAllInterviewID()
{
// Arrange
var id = "11";
// Act
var result = await _client.GetAsync($"Home/GetInfo/{id}");
// Assert
Assert.AreEqual(System.Net.HttpStatusCode.OK, result.StatusCode);
}
}
This example is closer to Integration testing rather than Unit-testing. If you want to have unit-test then you need to do the following things
BaseDataAccess _datatAccess this is a specific realization and it cannot be mocked (comparing to ILogger, IHostEnvironment etc)
move all your code from the controller to a separate class, and test this class.

Kafka Topic Unit Testing

I'm creating topic in Kafka with the below method,
public class KafkaTopicAdmin {
public void createTopic(final String topicName) {
final AdminClient client = getKafkaClient();
final List<NewTopic> topics = Collections.synchronizedList(new ArrayList<>());
final NewTopic newTopic = new NewTopic(topicName, connectionConfig.getNoOfPartition(), (short) connectionConfig.getNoOfReplicas());
topics.add(newTopic);
client.createTopics(topics);
}
private AdminClient getKafkaClient() {
final Map<String, Object> configs = new ConcurrentHashMap<>();
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "bootstrap-ip");
return AdminClient.create(configs);
}
}
and my test class is,
#EmbeddedKafka
public class KafkaTopicAdminTest {
private KafkaTopicAdmin kafkaTopicAdmin;
private AdminClient kafkaAdminClient;
#Before
public void setUp(){
kafkaTopicAdmin = new KafkaTopicAdmin();
Properties properties = new Properties();
properties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, StringUtils.arrayToCommaDelimitedString(new EmbeddedKafkaBroker(2).getBrokerAddresses()));
kafkaAdminClient = KafkaAdminClient.create(properties);
}
#Test
public void shouldCreateTopic() throws ExecutionException, InterruptedException {
kafkaTopicAdmin.createTopic("TestTopic");
ListTopicsOptions listTopicsOptions = new ListTopicsOptions();
listTopicsOptions.listInternal(true);
System.out.println("topics:" + kafkaAdminClient.listTopics(listTopicsOptions).names().get());
}
}
I'm getting the below error,
[AdminClient clientId=adminclient-1] Error connecting to node 127.0.0.1:0 (id: -2 rack: null)
java.net.BindException: Can't assign requested address
I use #EmbeddedKafka I just wanted to make sure the topic present in the list. Is this correct approach or any other suggestion please?
From the error it looks like you specified the bootstrap.servers property with no port: 127.0.0.1:0
This property takes the port of your Kafka bootstrap server too, which by default is 9092, so try this:
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "bootstrap-server-ip:9092");

MapReduce - Mock with Mokito

I have the a reducer class that I wanted to write test cases:
Reduce class:
public class MyReducer extends Reducer<Text, Text, NullWritable, Text> {
private static final Logger LOG = LogManager.getLogger(MyReducer.class);
public static List<String> l1 = new ArrayList<String>();
String id = null;
private MultipleOutputs<NullWritable, Text> mos;
#Override
public void setup(final Context context) throws IOException, InterruptedException {
mos = new MultipleOutputs<NullWritable, Text>(context);
final Path[] uris = DistributedCache.getLocalCacheFiles(context.getConfiguration());
try {
final BufferedReader readBuffer1 = new BufferedReader(new FileReader(uris[0].toString()));
String line;
while ((line = readBuffer1.readLine()) != null) {
l1.add(line);
}
readBuffer1.close();
} catch (Exception e) {
LOG.error(e);
}
}
public void reduce(final Text key, final Iterable<Text> values, final Context context)
throws IOException, InterruptedException {
final String[] key1 = key.toString().split("-");
final String keyA = key1[10];
final String date = key1[1];
/* Some condition check */
mos.write(NullWritable.get(), new Text(inputEventValue), keyA + "//date=" +
date.substring(0, 4) + "-" + date.substring(4, 6));
}
#Override
public void cleanup(final Context context) throws IOException, InterruptedException {
mos.close();
}
}
Test Case looks like :
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private MyReducer.Context mockContext;
MyReducer reducer;
MultipleOutputs<NullWritable, Text> mos;
#Before
public void setUp() {
reducer = new MyReducer();
}
#Test
public void myReducerTest() throws Exception {
MyReducer spy = PowerMockito.spy(new MyReducer());
doNothing().when(spy).setup(mockContext);
mos = new MultipleOutputs<NullWritable, Text>(mockContext);
List<Text> sline = new ArrayList<>() ;
List<String> l1 = new ArrayList<String>();
l1.add(“1234”);
sline.add(new Text(“xyz”));
Whitebox.setInternalState(MyReducer.class,”l1", l1);
Whitebox.setInternalState(MyReducer.class,"mos",mos);
reducer.reduce(new Text(“xyz-20200101-1234),sline,mockContext);
}
#After
public void tearDown() throws Exception {
/*
* this will do the clean up part
*/
verifyNoMoreInteractions(mockContext);
}
When running in Debug mode it goes to the reducer's reduce method and fails with NullPointerException where mos write statement is?
Complete Stack trace:
java.lang.NullPointerException
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.getNamedOutputsList(MultipleOutputs.java:196)
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.<init>(MultipleOutputs.java:324)
at MyTest.myeducerTest
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
Mocking mos errors as mos is not a static.
Any suggestion.
Junit - ReduceDriver, withInput, withOutput,testRun doesn't work.
Thanks.
I tried mocking Multiple outputs as suggested:
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
#Mock
private MyReducer.Context mockContext;
List<String> namedOut = new ArrayList<>();
namedOut.add("NM1");
namedOut.add("NM2");
MultipleOutputs spy = PowerMockito.spy(new MultipleOutputs<>(mockContext));
when(spy, "getNamedOutputsList(mockContext)").thenReturn(namedOut);
But this gives me error : org.powermock.reflect.exceptions.MethodNotFoundException: no method found with name 'getNamedOutputsList(() anyObject())' with parameter types : [] in class org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.
Looks like you did not define what mockContext.getContext() should return for your test, so it returns null and fails.
Based on this sourcecode the methods looks like this (so you might use a different version):
private static List<String> getNamedOutputsList(JobContext job) {
List<String> names = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(
job.getConfiguration().get(MULTIPLE_OUTPUTS, ""), " ");
while (st.hasMoreTokens()) {
names.add(st.nextToken());
}
return names;
}
JobContext seems to refer to your mock Reducer.Context mockContext, so you need to define the appropriate behaviour so that it returns what it is supposed to return.
Note that this call originates from the constructor of MultipleOutputs.
Also take note of the static getCountersEnabled method that is invoked from the constructor and interacts with the context.
Mocking mos errors as mos is not a static.
You could probably use reflections to put a mocked version of mos into your MyReducer class.
Check here for some example on how to mock a private static field.
Edit:
If you try to mock the conig do it like this:
Configuration config = Mockito.mock(Configuration.class);
when(mockContext.getConfiguration()).thenReturn(config);
As far as I see the get that are invoked on the configuration object always provide a default value, so it shouldn't matter if the key/value pair is in there or not.

How to mock httpcontext in service

How can the httpcontext in this service be mocked?
When I attempt to unit test this service it complains about the httpcontext being null.
What can be used in place of the httpcontext? I'm using webforms not mvc. I have seen multiple posts on faking the httpcontext class but not using webforms.
public class FileService : IFileService
{
public string GetEmployeePicLocation(Employee employee)
{
string AgentFilesDirectory = "~\\AgentFiles\\";
Image newImage = new Image();
DirectoryInfo diSubPath =
new DirectoryInfo(HttpContext.Current.Server
.MapPath(AgentFilesDirectory + employee.User_Name));
string localDIR = AgentFilesDirectory + employee.User_Name + "\\";
string defaultDIR = AgentFilesDirectory + "nopic\\nopic.jpg";
string strFile;
if (diSubPath.Exists)
{
FileInfo[] arrJPG = diSubPath.GetFiles("*.jpg");
FileInfo[] arrPNG = diSubPath.GetFiles("*.png");
if (!(arrJPG.Length == 0) || !(arrPNG.Length == 0))
{
foreach (FileInfo f in diSubPath.GetFiles("*.jpg"))
{
newImage.ImageUrl = localDIR + employee.PicFile;
}
foreach (FileInfo f in diSubPath.GetFiles("*.png"))
{
newImage.ImageUrl = localDIR + employee.PicFile;
}
}
else
{
newImage.ImageUrl = defaultDIR;
}
}
if (!(diSubPath.Exists))
{
newImage.ImageUrl = defaultDIR;
}
return newImage.ImageUrl.ToString();
}
}
Even though you're not doing MVC, HttpContextBase is defined in the System.Web assembly (or if you're using .Net 3.5, in System.Web.Abstractions) and so you can still using it. Change your class to take an instance of HttpContextBase, and you can create a mock and set it up as needed.
Your class would look like this:
public class FileService : IFileService
{
private HttpContextBase httpContext;
public FileService(HttpContextBase httpContext) {
this.httpContext = httpContext;
}
Then in your test:
var httpContextMock = new Mock<HttpContextBase>();
httpContextMock.Setup(x => x.SkipAuthorization).Returns(true);
var fileService = new FileService(httpContextMock.Object);
You'll need to also use some DI pattern so that the HttpContextBase instance is passed in either your constructor or via property injection.
You'll have to do something similar I think for your calls to the various System.IO classes, unless you actually have a place on the file system setup and ready to do for your tests.
I would use IoC and introduce some interface property that would provide access to select HttpContext properties. When testing you just use your implementation which would feed method with needed values during the test.
here is some pesudo-code:
public class FileService : IFileService
{
// injected property
public IHttpContext CurrentContex {get;set;}
public string GetEmployeePicLocation(Employee employee)
{
string AgentFilesDirectory = "~\\AgentFiles\\";
Image newImage = new Image();
DirectoryInfo diSubPath = new DirectoryInfo(CurrentContex.Server.MapPath(AgentFilesDirectory + employee.User_Name));
// ...
}
}
PS: I think you're looking for a HttpContext stub. Please have a look here http://martinfowler.com/articles/mocksArentStubs.html
I see that you got some answers on how to mock it, just thought I'd suggest an alternate method that may be simpler when it takes effort to replace a static access;
If you move the access to HttpContext to a virtual method;
protected virtual DirectoryInfo GetEmployeeDirInfo(Employee employee)
{
return new DirectoryInfo(
HttpContext.Current.Server.MapPath(AgentFilesDirectory + employee.User_Name));
}
and replace the old line doing the access with;
DirectoryInfo diSubPath = GetEmployeeDirInfo(employee);
...you can suddenly trivially replace the access by "mocking" the class manually;
internal class FileServiceMock : FileService
{
protected override DirectoryInfo GetEmployeeDirInfo(Employee employee)
{
return new DirectoryInfo("C:\\Temp");
}
}
...and just test FileServiceMock in your test.
void Testmethod() {
FileService service = new FileServiceMock();
...
alternatively use HostingEnvironment.MapPath . .it doesnt need httpcontext . .avoid httpcontext

Is it possible to unit test BundleConfig in MVC4?

As far as I can tell, the answer is no. The issue I'm seeing comes from the Include(params string[]) method in the System.Web.Optimization.Bundle class. Internally this invokes System.Web.Optimization.IncludeDirectory(string, string, bool), which in turn uses this code:
DirectoryInfo directoryInfo = new DirectoryInfo(
HttpContext.Current.Server.MapPath(directoryVirtualPath));
While it is possible to set HttpContext.Current during a unit test, I can't figure out how to make its .Server.MapPath(string directoryVirtualPath) return a non-null string. Since the DirectoryInfo(string) constructor throws an exception when passed a null argument, such a test will always fail.
What is the .NET team's recommendation for this? Do we have to unit test bundling configurations as part of integration tests or user acceptance tests?
I have some good news for you, for RTM we added a new static property on BundleTable to enable more unit tests:
public static Func<string, string> MapPathMethod;
Edit Updated with a test virtual path provider:
So you can do something like this:
public class TestVirtualPathProvider : VirtualPathProvider {
private string NormalizeVirtualPath(string virtualPath, bool isDirectory = false) {
if (!virtualPath.StartsWith("~")) {
virtualPath = "~" + virtualPath;
}
virtualPath = virtualPath.Replace('\\', '/');
// Normalize directories to always have an ending "/"
if (isDirectory && !virtualPath.EndsWith("/")) {
return virtualPath + "/";
}
return virtualPath;
}
// Files on disk (virtualPath -> file)
private Dictionary<string, VirtualFile> _fileMap = new Dictionary<string, VirtualFile>();
private Dictionary<string, VirtualFile> FileMap {
get { return _fileMap; }
}
public void AddFile(VirtualFile file) {
FileMap[NormalizeVirtualPath(file.VirtualPath)] = file;
}
private Dictionary<string, VirtualDirectory> _directoryMap = new Dictionary<string, VirtualDirectory>();
private Dictionary<string, VirtualDirectory> DirectoryMap {
get { return _directoryMap; }
}
public void AddDirectory(VirtualDirectory dir) {
DirectoryMap[NormalizeVirtualPath(dir.VirtualPath, isDirectory: true)] = dir;
}
public override bool FileExists(string virtualPath) {
return FileMap.ContainsKey(NormalizeVirtualPath(virtualPath));
}
public override bool DirectoryExists(string virtualDir) {
return DirectoryMap.ContainsKey(NormalizeVirtualPath(virtualDir, isDirectory: true));
}
public override VirtualFile GetFile(string virtualPath) {
return FileMap[NormalizeVirtualPath(virtualPath)];
}
public override VirtualDirectory GetDirectory(string virtualDir) {
return DirectoryMap[NormalizeVirtualPath(virtualDir, isDirectory: true)];
}
internal class TestVirtualFile : VirtualFile {
public TestVirtualFile(string virtualPath, string contents)
: base(virtualPath) {
Contents = contents;
}
public string Contents { get; set; }
public override Stream Open() {
return new MemoryStream(UTF8Encoding.Default.GetBytes(Contents));
}
}
internal class TestVirtualDirectory : VirtualDirectory {
public TestVirtualDirectory(string virtualPath)
: base(virtualPath) {
}
public List<VirtualFile> _directoryFiles = new List<VirtualFile>();
public List<VirtualFile> DirectoryFiles {
get {
return _directoryFiles;
}
}
public List<VirtualDirectory> _subDirs = new List<VirtualDirectory>();
public List<VirtualDirectory> SubDirectories {
get {
return _subDirs;
}
}
public override IEnumerable Files {
get {
return DirectoryFiles;
}
}
public override IEnumerable Children {
get { throw new NotImplementedException(); }
}
public override IEnumerable Directories {
get {
return SubDirectories;
}
}
}
And then write a unit test using that like so:
[TestMethod]
public void StyleBundleCustomVPPIncludeVersionSelectsTest() {
//Setup the vpp to contain the files/directories
TestVirtualPathProvider vpp = new TestVirtualPathProvider();
var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/");
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct"));
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong"));
vpp.AddDirectory(directory);
// Setup the bundle
ScriptBundle bundle = new ScriptBundle("~/bundles/test");
bundle.Items.VirtualPathProvider = vpp;
bundle.Include("~/dir/style{version}.css");
// Verify the bundle repsonse
BundleContext context = SetupContext(bundle, vpp);
BundleResponse response = bundle.GetBundleResponse(context);
Assert.AreEqual(#"correct", response.Content);
}
In .Net 4.5 things have slightly changed. Here is a working version of the approved answer updated to accommodate these changes (I am using Autofac). Note the "GenerateBundleResponse" instead of "GetBundleResponse":
[Fact]
public void StyleBundleIncludesVersion()
{
//Setup the vpp to contain the files/directories
var vpp = new TestVirtualPathProvider();
var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/");
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct"));
directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong"));
vpp.AddDirectory(directory);
// Setup the bundle
var bundleCollection = new BundleCollection();
var bundle = new ScriptBundle("~/bundles/test");
BundleTable.VirtualPathProvider = vpp;
bundle.Include("~/dir/style{version}.css");
bundleCollection.Add(bundle);
var mockHttpContext = new Mock<HttpContextBase>();
// Verify the bundle repsonse
var context = new BundleContext(mockHttpContext.Object, bundleCollection, vpp.ToString());
var response = bundle.GenerateBundleResponse(context);
Assert.Equal(#"correct", response.Content);
}